aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/Kconfig7
-rw-r--r--drivers/staging/Makefile4
-rw-r--r--drivers/staging/android/TODO2
-rw-r--r--drivers/staging/android/ion/ion.c36
-rw-r--r--drivers/staging/android/ion/ion.h10
-rw-r--r--drivers/staging/android/vsoc.c8
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c7
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c2
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c2
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c80
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.h5
-rw-r--r--drivers/staging/erofs/Documentation/filesystems/erofs.txt209
-rw-r--r--drivers/staging/erofs/Kconfig151
-rw-r--r--drivers/staging/erofs/Makefile13
-rw-r--r--drivers/staging/erofs/TODO46
-rw-r--r--drivers/staging/erofs/compress.h62
-rw-r--r--drivers/staging/erofs/data.c400
-rw-r--r--drivers/staging/erofs/decompressor.c335
-rw-r--r--drivers/staging/erofs/dir.c151
-rw-r--r--drivers/staging/erofs/erofs_fs.h322
-rw-r--r--drivers/staging/erofs/include/linux/tagptr.h110
-rw-r--r--drivers/staging/erofs/include/trace/events/erofs.h256
-rw-r--r--drivers/staging/erofs/inode.c332
-rw-r--r--drivers/staging/erofs/internal.h642
-rw-r--r--drivers/staging/erofs/namei.c256
-rw-r--r--drivers/staging/erofs/super.c701
-rw-r--r--drivers/staging/erofs/unzip_pagevec.h169
-rw-r--r--drivers/staging/erofs/unzip_vle.c1591
-rw-r--r--drivers/staging/erofs/unzip_vle.h196
-rw-r--r--drivers/staging/erofs/utils.c353
-rw-r--r--drivers/staging/erofs/xattr.c704
-rw-r--r--drivers/staging/erofs/xattr.h97
-rw-r--r--drivers/staging/erofs/zmap.c463
-rw-r--r--drivers/staging/exfat/Kconfig49
-rw-r--r--drivers/staging/exfat/Makefile10
-rw-r--r--drivers/staging/exfat/TODO12
-rw-r--r--drivers/staging/exfat/exfat.h971
-rw-r--r--drivers/staging/exfat/exfat_blkdev.c136
-rw-r--r--drivers/staging/exfat/exfat_cache.c724
-rw-r--r--drivers/staging/exfat/exfat_core.c3701
-rw-r--r--drivers/staging/exfat/exfat_nls.c404
-rw-r--r--drivers/staging/exfat/exfat_super.c4049
-rw-r--r--drivers/staging/exfat/exfat_upcase.c740
-rw-r--r--drivers/staging/fbtft/fb_hx8340bn.c2
-rw-r--r--drivers/staging/fbtft/fb_hx8347d.c2
-rw-r--r--drivers/staging/fbtft/fb_ili9163.c2
-rw-r--r--drivers/staging/fbtft/fb_ili9320.c2
-rw-r--r--drivers/staging/fbtft/fb_ili9325.c2
-rw-r--r--drivers/staging/fbtft/fb_pcd8544.c4
-rw-r--r--drivers/staging/fbtft/fb_s6d1121.c2
-rw-r--r--drivers/staging/fbtft/fb_ssd1289.c2
-rw-r--r--drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt71
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/TODO1
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h15
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/dpsw.c51
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/dpsw.h56
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c44
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw.c309
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw.h4
-rw-r--r--drivers/staging/gasket/apex_driver.c22
-rw-r--r--drivers/staging/gasket/gasket_ioctl.c12
-rw-r--r--drivers/staging/goldfish/goldfish_audio.c4
-rw-r--r--drivers/staging/greybus/Documentation/firmware/authenticate.c46
-rw-r--r--drivers/staging/greybus/Documentation/firmware/firmware.c46
-rw-r--r--drivers/staging/greybus/Kconfig27
-rw-r--r--drivers/staging/greybus/Makefile22
-rw-r--r--drivers/staging/greybus/arche-platform.c2
-rw-r--r--drivers/staging/greybus/arpc.h109
-rw-r--r--drivers/staging/greybus/audio_apbridgea.c3
-rw-r--r--drivers/staging/greybus/audio_apbridgea.h26
-rw-r--r--drivers/staging/greybus/audio_codec.h4
-rw-r--r--drivers/staging/greybus/audio_gb.c4
-rw-r--r--drivers/staging/greybus/audio_manager.c2
-rw-r--r--drivers/staging/greybus/authentication.c3
-rw-r--r--drivers/staging/greybus/bootrom.c2
-rw-r--r--drivers/staging/greybus/bundle.c252
-rw-r--r--drivers/staging/greybus/bundle.h89
-rw-r--r--drivers/staging/greybus/camera.c2
-rw-r--r--drivers/staging/greybus/connection.c942
-rw-r--r--drivers/staging/greybus/connection.h128
-rw-r--r--drivers/staging/greybus/control.c584
-rw-r--r--drivers/staging/greybus/control.h57
-rw-r--r--drivers/staging/greybus/core.c349
-rw-r--r--drivers/staging/greybus/debugfs.c30
-rw-r--r--drivers/staging/greybus/es2.c1466
-rw-r--r--drivers/staging/greybus/firmware.h4
-rw-r--r--drivers/staging/greybus/fw-core.c2
-rw-r--r--drivers/staging/greybus/fw-download.c2
-rw-r--r--drivers/staging/greybus/fw-management.c2
-rw-r--r--drivers/staging/greybus/gb-camera.h2
-rw-r--r--drivers/staging/greybus/gbphy.c2
-rw-r--r--drivers/staging/greybus/gbphy.h2
-rw-r--r--drivers/staging/greybus/gpio.c2
-rw-r--r--drivers/staging/greybus/greybus.h152
-rw-r--r--drivers/staging/greybus/greybus_authentication.h48
-rw-r--r--drivers/staging/greybus/greybus_firmware.h48
-rw-r--r--drivers/staging/greybus/greybus_id.h27
-rw-r--r--drivers/staging/greybus/greybus_manifest.h178
-rw-r--r--drivers/staging/greybus/greybus_protocols.h2222
-rw-r--r--drivers/staging/greybus/greybus_trace.h502
-rw-r--r--drivers/staging/greybus/hd.c256
-rw-r--r--drivers/staging/greybus/hd.h82
-rw-r--r--drivers/staging/greybus/hid.c3
-rw-r--r--drivers/staging/greybus/i2c.c24
-rw-r--r--drivers/staging/greybus/interface.c1263
-rw-r--r--drivers/staging/greybus/interface.h82
-rw-r--r--drivers/staging/greybus/light.c16
-rw-r--r--drivers/staging/greybus/log.c9
-rw-r--r--drivers/staging/greybus/loopback.c9
-rw-r--r--drivers/staging/greybus/manifest.c534
-rw-r--r--drivers/staging/greybus/manifest.h15
-rw-r--r--drivers/staging/greybus/module.c236
-rw-r--r--drivers/staging/greybus/module.h33
-rw-r--r--drivers/staging/greybus/operation.c1264
-rw-r--r--drivers/staging/greybus/operation.h224
-rw-r--r--drivers/staging/greybus/power_supply.c3
-rw-r--r--drivers/staging/greybus/pwm.c2
-rw-r--r--drivers/staging/greybus/raw.c3
-rw-r--r--drivers/staging/greybus/sdio.c2
-rw-r--r--drivers/staging/greybus/spi.c2
-rw-r--r--drivers/staging/greybus/spilib.c2
-rw-r--r--drivers/staging/greybus/spilib.h2
-rw-r--r--drivers/staging/greybus/svc.c1398
-rw-r--r--drivers/staging/greybus/svc.h101
-rw-r--r--drivers/staging/greybus/svc_watchdog.c197
-rw-r--r--drivers/staging/greybus/tools/loopback_test.c2
-rw-r--r--drivers/staging/greybus/uart.c2
-rw-r--r--drivers/staging/greybus/usb.c2
-rw-r--r--drivers/staging/greybus/vibrator.c3
-rw-r--r--drivers/staging/iio/accel/adis16240.c5
-rw-r--r--drivers/staging/iio/adc/ad7192.c175
-rw-r--r--drivers/staging/iio/adc/ad7192.h37
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c12
-rw-r--r--drivers/staging/isdn/hysdn/Kconfig2
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_net.c2
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_procconf.c2
-rw-r--r--drivers/staging/kpc2000/kpc2000/cell_probe.c18
-rw-r--r--drivers/staging/kpc2000/kpc2000/core.c18
-rw-r--r--drivers/staging/kpc2000/kpc2000_i2c.c4
-rw-r--r--drivers/staging/kpc2000/kpc2000_spi.c3
-rw-r--r--drivers/staging/kpc2000/kpc_dma/fileops.c8
-rw-r--r--drivers/staging/media/Kconfig4
-rw-r--r--drivers/staging/media/Makefile2
-rw-r--r--drivers/staging/media/allegro-dvt/allegro-core.c4
-rw-r--r--drivers/staging/media/bcm2048/Kconfig14
-rw-r--r--drivers/staging/media/bcm2048/Makefile2
-rw-r--r--drivers/staging/media/bcm2048/TODO24
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c2689
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.h26
-rw-r--r--drivers/staging/media/davinci_vpfe/Kconfig13
-rw-r--r--drivers/staging/media/davinci_vpfe/Makefile11
-rw-r--r--drivers/staging/media/davinci_vpfe/TODO38
-rw-r--r--drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt154
-rw-r--r--drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h1287
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c1852
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.h174
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c1038
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h556
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.c1070
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.h228
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h90
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c2097
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.h200
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif_regs.h291
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c1995
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.h241
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe.h83
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c716
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h90
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c1646
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.h150
-rw-r--r--drivers/staging/media/hantro/Kconfig2
-rw-r--r--drivers/staging/media/hantro/Makefile7
-rw-r--r--drivers/staging/media/hantro/hantro.h51
-rw-r--r--drivers/staging/media/hantro/hantro_drv.c110
-rw-r--r--drivers/staging/media/hantro/hantro_g1_h264_dec.c292
-rw-r--r--drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c14
-rw-r--r--drivers/staging/media/hantro/hantro_g1_vp8_dec.c503
-rw-r--r--drivers/staging/media/hantro/hantro_h1_jpeg_enc.c11
-rw-r--r--drivers/staging/media/hantro/hantro_h264.c646
-rw-r--r--drivers/staging/media/hantro/hantro_hw.h80
-rw-r--r--drivers/staging/media/hantro/hantro_v4l2.c11
-rw-r--r--drivers/staging/media/hantro/hantro_vp8.c201
-rw-r--r--drivers/staging/media/hantro/rk3288_vpu_hw.c41
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_hw.c39
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c12
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c14
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c595
-rw-r--r--drivers/staging/media/imx/Kconfig5
-rw-r--r--drivers/staging/media/imx/Makefile3
-rw-r--r--drivers/staging/media/imx/imx-media-csc-scaler.c925
-rw-r--r--drivers/staging/media/imx/imx-media-dev.c28
-rw-r--r--drivers/staging/media/imx/imx-media-internal-sd.c4
-rw-r--r--drivers/staging/media/imx/imx-media-utils.c2
-rw-r--r--drivers/staging/media/imx/imx-media.h12
-rw-r--r--drivers/staging/media/imx/imx6-mipi-csi2.c12
-rw-r--r--drivers/staging/media/imx/imx7-media-csi.c34
-rw-r--r--drivers/staging/media/imx/imx7-mipi-csis.c4
-rw-r--r--drivers/staging/media/ipu3/ipu3-tables.h4
-rw-r--r--drivers/staging/media/ipu3/ipu3.c3
-rw-r--r--drivers/staging/media/meson/vdec/esparser.c4
-rw-r--r--drivers/staging/media/omap4iss/iss.c1
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c40
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h2
-rw-r--r--drivers/staging/media/soc_camera/soc_camera.c2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.c63
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.h7
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.c2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h264.c4
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.c8
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_regs.h2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.c28
-rw-r--r--drivers/staging/media/tegra-vde/Kconfig2
-rw-r--r--drivers/staging/most/cdev/cdev.c4
-rw-r--r--drivers/staging/most/core.c4
-rw-r--r--drivers/staging/most/dim2/dim2.c21
-rw-r--r--drivers/staging/most/dim2/hal.c99
-rw-r--r--drivers/staging/most/dim2/hal.h4
-rw-r--r--drivers/staging/most/net/net.c3
-rw-r--r--drivers/staging/most/sound/sound.c5
-rw-r--r--drivers/staging/most/video/video.c3
-rw-r--r--drivers/staging/mt7621-dma/mtk-hsdma.c4
-rw-r--r--drivers/staging/mt7621-pci/pci-mt7621.c12
-rw-r--r--drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c5
-rw-r--r--drivers/staging/nvec/nvec.c8
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c2
-rw-r--r--drivers/staging/octeon/ethernet.c16
-rw-r--r--drivers/staging/olpc_dcon/TODO4
-rw-r--r--drivers/staging/pi433/Documentation/pi433.txt2
-rw-r--r--drivers/staging/ralink-gdma/ralink-gdma.c4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c141
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c11
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c14
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_security.c41
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c19
-rw-r--r--drivers/staging/rtl8188eu/hal/bb_cfg.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rf_cfg.c14
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c143
-rw-r--r--drivers/staging/rtl8188eu/include/hal8188e_phy_reg.h881
-rw-r--r--drivers/staging/rtl8188eu/include/hal_intf.h2
-rw-r--r--drivers/staging/rtl8188eu/include/mlme_osdep.h1
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h1
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c5
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c5
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c3
-rw-r--r--drivers/staging/rtl8192e/Kconfig1
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c12
-rw-r--r--drivers/staging/rtl8192e/rtllib.h5
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_ccmp.c206
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c24
-rw-r--r--drivers/staging/rtl8192u/Kconfig2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/dot11d.c10
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h42
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c204
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c22
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c635
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c1
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c14
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c142
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c43
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c12
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h17
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c18
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.c11
-rw-r--r--drivers/staging/rtl8192u/r8190_rtl8256.c42
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c112
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c2
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.c2
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c59
-rw-r--r--drivers/staging/rtl8712/os_intfs.c35
-rw-r--r--drivers/staging/rtl8712/recv_linux.c18
-rw-r--r--drivers/staging/rtl8712/recv_osdep.h16
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.c14
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c54
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c46
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.h8
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.h7
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c5
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.c16
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.h4
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c34
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.h8
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp.c9
-rw-r--r--drivers/staging/rtl8712/rtl871x_pwrctrl.c10
-rw-r--r--drivers/staging/rtl8712/rtl871x_pwrctrl.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c22
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_rf.h3
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.c29
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.h4
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c65
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.h20
-rw-r--r--drivers/staging/rtl8712/usb_intf.c2
-rw-r--r--drivers/staging/rtl8712/usb_osintf.h4
-rw-r--r--drivers/staging/rtl8712/wifi.h8
-rw-r--r--drivers/staging/rtl8712/xmit_linux.c2
-rw-r--r--drivers/staging/rtl8723bs/Makefile1
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ap.c113
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_cmd.c11
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_debug.c1307
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_io.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ioctl_set.c7
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c15
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_pwrctrl.c121
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_security.c3
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_wlan_util.c7
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c6
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h1
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_btcoex.c44
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com.c5
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com_phycfg.c18
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_intf.c2
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_phy.c157
-rw-r--r--drivers/staging/rtl8723bs/hal/odm.c19
-rw-r--r--drivers/staging/rtl8723bs/hal/odm.h4
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_CfoTracking.c5
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_HWConfig.c7
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c15
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c8
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c7
-rw-r--r--drivers/staging/rtl8723bs/include/autoconf.h4
-rw-r--r--drivers/staging/rtl8723bs/include/drv_types.h8
-rw-r--r--drivers/staging/rtl8723bs/include/hal_btcoex.h8
-rw-r--r--drivers/staging/rtl8723bs/include/hal_com_phycfg.h17
-rw-r--r--drivers/staging/rtl8723bs/include/hal_intf.h2
-rw-r--r--drivers/staging/rtl8723bs/include/hal_phy_cfg.h4
-rw-r--r--drivers/staging/rtl8723bs/include/osdep_intf.h2
-rw-r--r--drivers/staging/rtl8723bs/include/osdep_service.h10
-rw-r--r--drivers/staging/rtl8723bs/include/osdep_service_linux.h14
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_debug.h77
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mlme.h20
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mlme_ext.h3
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_recv.h16
-rw-r--r--drivers/staging/rtl8723bs/include/sta_info.h2
-rw-r--r--drivers/staging/rtl8723bs/include/wifi.h14
-rw-r--r--drivers/staging/rtl8723bs/include/wlan_bssdef.h2
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c10
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_linux.c7
-rw-r--r--drivers/staging/rtl8723bs/os_dep/os_intfs.c21
-rw-r--r--drivers/staging/rtl8723bs/os_dep/osdep_service.c4
-rw-r--r--drivers/staging/rtl8723bs/os_dep/rtw_proc.c779
-rw-r--r--drivers/staging/rtl8723bs/os_dep/rtw_proc.h37
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_intf.c5
-rw-r--r--drivers/staging/rtl8723bs/os_dep/wifi_regd.c5
-rw-r--r--drivers/staging/rts5208/ms.c2
-rw-r--r--drivers/staging/rts5208/rtsx_transport.c12
-rw-r--r--drivers/staging/rts5208/sd.c28
-rw-r--r--drivers/staging/sm750fb/ddk750.h3
-rw-r--r--drivers/staging/sm750fb/ddk750_swi2c.c3
-rw-r--r--drivers/staging/sm750fb/ddk750_swi2c.h3
-rw-r--r--drivers/staging/uwb/Kconfig72
-rw-r--r--drivers/staging/uwb/Makefile32
-rw-r--r--drivers/staging/uwb/TODO8
-rw-r--r--drivers/staging/uwb/address.c352
-rw-r--r--drivers/staging/uwb/allocator.c374
-rw-r--r--drivers/staging/uwb/beacon.c595
-rw-r--r--drivers/staging/uwb/driver.c143
-rw-r--r--drivers/staging/uwb/drp-avail.c278
-rw-r--r--drivers/staging/uwb/drp-ie.c305
-rw-r--r--drivers/staging/uwb/drp.c842
-rw-r--r--drivers/staging/uwb/est.c450
-rw-r--r--drivers/staging/uwb/hwa-rc.c929
-rw-r--r--drivers/staging/uwb/i1480/Makefile2
-rw-r--r--drivers/staging/uwb/i1480/dfu/Makefile10
-rw-r--r--drivers/staging/uwb/i1480/dfu/dfu.c198
-rw-r--r--drivers/staging/uwb/i1480/dfu/i1480-dfu.h246
-rw-r--r--drivers/staging/uwb/i1480/dfu/mac.c496
-rw-r--r--drivers/staging/uwb/i1480/dfu/phy.c190
-rw-r--r--drivers/staging/uwb/i1480/dfu/usb.c448
-rw-r--r--drivers/staging/uwb/i1480/i1480-est.c85
-rw-r--r--drivers/staging/uwb/ie-rcv.c42
-rw-r--r--drivers/staging/uwb/ie.c366
-rw-r--r--drivers/staging/uwb/include/debug-cmd.h57
-rw-r--r--drivers/staging/uwb/include/spec.h767
-rw-r--r--drivers/staging/uwb/include/umc.h192
-rw-r--r--drivers/staging/uwb/include/whci.h102
-rw-r--r--drivers/staging/uwb/lc-dev.c457
-rw-r--r--drivers/staging/uwb/lc-rc.c569
-rw-r--r--drivers/staging/uwb/neh.c606
-rw-r--r--drivers/staging/uwb/pal.c128
-rw-r--r--drivers/staging/uwb/radio.c196
-rw-r--r--drivers/staging/uwb/reset.c379
-rw-r--r--drivers/staging/uwb/rsv.c1000
-rw-r--r--drivers/staging/uwb/scan.c120
-rw-r--r--drivers/staging/uwb/umc-bus.c211
-rw-r--r--drivers/staging/uwb/umc-dev.c94
-rw-r--r--drivers/staging/uwb/umc-drv.c31
-rw-r--r--drivers/staging/uwb/uwb-debug.c354
-rw-r--r--drivers/staging/uwb/uwb-internal.h366
-rw-r--r--drivers/staging/uwb/uwb.h817
-rw-r--r--drivers/staging/uwb/uwbd.c356
-rw-r--r--drivers/staging/uwb/whc-rc.c467
-rw-r--r--drivers/staging/uwb/whci.c257
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c29
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-common.h1
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c4
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c5
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c38
-rw-r--r--drivers/staging/vt6656/rxtx.c10
-rw-r--r--drivers/staging/vt6656/usbpipe.c2
-rw-r--r--drivers/staging/wilc1000/microchip,wilc1000,sdio.txt8
-rw-r--r--drivers/staging/wilc1000/microchip,wilc1000,spi.txt8
-rw-r--r--drivers/staging/wilc1000/wilc_hif.c70
-rw-r--r--drivers/staging/wilc1000/wilc_hif.h6
-rw-r--r--drivers/staging/wilc1000/wilc_mon.c3
-rw-r--r--drivers/staging/wilc1000/wilc_netdev.c78
-rw-r--r--drivers/staging/wilc1000/wilc_sdio.c18
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.c63
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.h3
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.c135
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.h19
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.c78
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.h4
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_if.h3
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c210
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c44
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c2
-rw-r--r--drivers/staging/wusbcore/Documentation/wusb-cbaf130
-rw-r--r--drivers/staging/wusbcore/Documentation/wusb-design-overview.rst457
-rw-r--r--drivers/staging/wusbcore/Kconfig39
-rw-r--r--drivers/staging/wusbcore/Makefile28
-rw-r--r--drivers/staging/wusbcore/TODO8
-rw-r--r--drivers/staging/wusbcore/cbaf.c645
-rw-r--r--drivers/staging/wusbcore/crypto.c441
-rw-r--r--drivers/staging/wusbcore/dev-sysfs.c124
-rw-r--r--drivers/staging/wusbcore/devconnect.c1085
-rw-r--r--drivers/staging/wusbcore/host/Kconfig28
-rw-r--r--drivers/staging/wusbcore/host/Makefile3
-rw-r--r--drivers/staging/wusbcore/host/hwa-hc.c875
-rw-r--r--drivers/staging/wusbcore/host/whci/Makefile14
-rw-r--r--drivers/staging/wusbcore/host/whci/asl.c376
-rw-r--r--drivers/staging/wusbcore/host/whci/debug.c153
-rw-r--r--drivers/staging/wusbcore/host/whci/hcd.c356
-rw-r--r--drivers/staging/wusbcore/host/whci/hw.c93
-rw-r--r--drivers/staging/wusbcore/host/whci/init.c177
-rw-r--r--drivers/staging/wusbcore/host/whci/int.c82
-rw-r--r--drivers/staging/wusbcore/host/whci/pzl.c404
-rw-r--r--drivers/staging/wusbcore/host/whci/qset.c831
-rw-r--r--drivers/staging/wusbcore/host/whci/whcd.h202
-rw-r--r--drivers/staging/wusbcore/host/whci/whci-hc.h401
-rw-r--r--drivers/staging/wusbcore/host/whci/wusb.c210
-rw-r--r--drivers/staging/wusbcore/include/association.h151
-rw-r--r--drivers/staging/wusbcore/include/wusb-wa.h304
-rw-r--r--drivers/staging/wusbcore/include/wusb.h362
-rw-r--r--drivers/staging/wusbcore/mmc.c303
-rw-r--r--drivers/staging/wusbcore/pal.c45
-rw-r--r--drivers/staging/wusbcore/reservation.c110
-rw-r--r--drivers/staging/wusbcore/rh.c426
-rw-r--r--drivers/staging/wusbcore/security.c599
-rw-r--r--drivers/staging/wusbcore/wa-hc.c88
-rw-r--r--drivers/staging/wusbcore/wa-hc.h467
-rw-r--r--drivers/staging/wusbcore/wa-nep.c289
-rw-r--r--drivers/staging/wusbcore/wa-rpipe.c539
-rw-r--r--drivers/staging/wusbcore/wa-xfer.c2927
-rw-r--r--drivers/staging/wusbcore/wusbhc.c490
-rw-r--r--drivers/staging/wusbcore/wusbhc.h487
467 files changed, 45391 insertions, 43978 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 0b8a614be11e..6f1fa4c849a1 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -112,14 +112,17 @@ source "drivers/staging/gasket/Kconfig"
source "drivers/staging/axis-fifo/Kconfig"
-source "drivers/staging/erofs/Kconfig"
-
source "drivers/staging/fieldbus/Kconfig"
source "drivers/staging/kpc2000/Kconfig"
source "drivers/staging/isdn/Kconfig"
+source "drivers/staging/wusbcore/Kconfig"
+source "drivers/staging/uwb/Kconfig"
+
+source "drivers/staging/exfat/Kconfig"
+
source "drivers/staging/qlge/Kconfig"
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 741152511a10..a90f9b308c8d 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -46,8 +46,10 @@ obj-$(CONFIG_DMA_RALINK) += ralink-gdma/
obj-$(CONFIG_SOC_MT7621) += mt7621-dts/
obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
-obj-$(CONFIG_EROFS_FS) += erofs/
obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
obj-$(CONFIG_KPC2000) += kpc2000/
obj-$(CONFIG_ISDN_CAPI) += isdn/
+obj-$(CONFIG_UWB) += uwb/
+obj-$(CONFIG_USB_WUSB) += wusbcore/
+obj-$(CONFIG_EXFAT_FS) += exfat/
obj-$(CONFIG_QLGE) += qlge/
diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO
index fbf015cc6d62..767dd98fd92d 100644
--- a/drivers/staging/android/TODO
+++ b/drivers/staging/android/TODO
@@ -6,8 +6,6 @@ TODO:
ion/
- - Add dt-bindings for remaining heaps (chunk and carveout heaps). This would
- involve putting appropriate bindings in a memory node for Ion to find.
- Split /dev/ion up into multiple nodes (e.g. /dev/ion/heap0)
- Better test framework (integration with VGEM was suggested)
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 92c2914239e3..e6b1ca141b93 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -30,32 +30,6 @@ static struct ion_device *internal_dev;
static int heap_id;
/* this function should only be called while dev->lock is held */
-static void ion_buffer_add(struct ion_device *dev,
- struct ion_buffer *buffer)
-{
- struct rb_node **p = &dev->buffers.rb_node;
- struct rb_node *parent = NULL;
- struct ion_buffer *entry;
-
- while (*p) {
- parent = *p;
- entry = rb_entry(parent, struct ion_buffer, node);
-
- if (buffer < entry) {
- p = &(*p)->rb_left;
- } else if (buffer > entry) {
- p = &(*p)->rb_right;
- } else {
- pr_err("%s: buffer already found.", __func__);
- BUG();
- }
- }
-
- rb_link_node(&buffer->node, parent, p);
- rb_insert_color(&buffer->node, &dev->buffers);
-}
-
-/* this function should only be called while dev->lock is held */
static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
struct ion_device *dev,
unsigned long len,
@@ -100,9 +74,6 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
INIT_LIST_HEAD(&buffer->attachments);
mutex_init(&buffer->lock);
- mutex_lock(&dev->buffer_lock);
- ion_buffer_add(dev, buffer);
- mutex_unlock(&dev->buffer_lock);
return buffer;
err1:
@@ -131,11 +102,6 @@ void ion_buffer_destroy(struct ion_buffer *buffer)
static void _ion_buffer_destroy(struct ion_buffer *buffer)
{
struct ion_heap *heap = buffer->heap;
- struct ion_device *dev = buffer->dev;
-
- mutex_lock(&dev->buffer_lock);
- rb_erase(&buffer->node, &dev->buffers);
- mutex_unlock(&dev->buffer_lock);
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
ion_heap_freelist_add(heap, buffer);
@@ -694,8 +660,6 @@ static int ion_device_create(void)
}
idev->debug_root = debugfs_create_dir("ion", NULL);
- idev->buffers = RB_ROOT;
- mutex_init(&idev->buffer_lock);
init_rwsem(&idev->lock);
plist_head_init(&idev->heaps);
internal_dev = idev;
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
index e291299fd35f..74914a266e25 100644
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -23,7 +23,6 @@
/**
* struct ion_buffer - metadata for a particular buffer
- * @node: node in the ion_device buffers tree
* @list: element in list of deferred freeable buffers
* @dev: back pointer to the ion_device
* @heap: back pointer to the heap the buffer came from
@@ -39,10 +38,7 @@
* @attachments: list of devices attached to this buffer
*/
struct ion_buffer {
- union {
- struct rb_node node;
- struct list_head list;
- };
+ struct list_head list;
struct ion_device *dev;
struct ion_heap *heap;
unsigned long flags;
@@ -61,14 +57,10 @@ void ion_buffer_destroy(struct ion_buffer *buffer);
/**
* struct ion_device - the metadata of the ion device node
* @dev: the actual misc device
- * @buffers: an rb tree of all the existing buffers
- * @buffer_lock: lock protecting the tree of buffers
* @lock: rwsem protecting the tree of heaps and clients
*/
struct ion_device {
struct miscdevice dev;
- struct rb_root buffers;
- struct mutex buffer_lock;
struct rw_semaphore lock;
struct plist_head heaps;
struct dentry *debug_root;
diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c
index 00a1ec7b9154..1240bb0317d9 100644
--- a/drivers/staging/android/vsoc.c
+++ b/drivers/staging/android/vsoc.c
@@ -437,12 +437,10 @@ static int handle_vsoc_cond_wait(struct file *filp, struct vsoc_cond_wait *arg)
return -EINVAL;
wake_time = ktime_set(arg->wake_time_sec, arg->wake_time_nsec);
- hrtimer_init_on_stack(&to->timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_ABS);
+ hrtimer_init_sleeper_on_stack(to, CLOCK_MONOTONIC,
+ HRTIMER_MODE_ABS);
hrtimer_set_expires_range_ns(&to->timer, wake_time,
current->timer_slack_ns);
-
- hrtimer_init_sleeper(to, current);
}
while (1) {
@@ -460,7 +458,7 @@ static int handle_vsoc_cond_wait(struct file *filp, struct vsoc_cond_wait *arg)
break;
}
if (to) {
- hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS);
+ hrtimer_sleeper_start_expires(to, HRTIMER_MODE_ABS);
if (likely(to->task))
freezable_schedule();
hrtimer_cancel(&to->timer);
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index aabcda3f9fc8..28603dfadce2 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -665,11 +665,6 @@ static void db2k_initialize_adc(struct comedi_device *dev)
db2k_initialize_tmrs(dev);
}
-static void db2k_initialize_dac(struct comedi_device *dev)
-{
- db2k_dac_disarm(dev);
-}
-
static int db2k_8255_cb(struct comedi_device *dev, int dir, int port, int data,
unsigned long iobase)
{
@@ -719,7 +714,7 @@ static int db2k_auto_attach(struct comedi_device *dev, unsigned long context)
return result;
db2k_initialize_adc(dev);
- db2k_initialize_dac(dev);
+ db2k_dac_disarm(dev);
s = &dev->subdevices[0];
/* ai subdevice */
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index c175227009f1..f98e3ae27bff 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -596,7 +596,7 @@ static int ni_request_ao_mite_channel(struct comedi_device *dev)
if (!mite_chan) {
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
dev_err(dev->class_dev,
- "failed to reserve mite dma channel for analog outut\n");
+ "failed to reserve mite dma channel for analog output\n");
return -EBUSY;
}
mite_chan->dir = COMEDI_OUTPUT;
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index 3cc40d2544be..54d7605e909f 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -1074,7 +1074,7 @@ static int usbduxsigma_pwm_period(struct comedi_device *dev,
unsigned int period)
{
struct usbduxsigma_private *devpriv = dev->private;
- int fx2delay = 255;
+ int fx2delay;
if (period < MIN_PWM_PERIOD)
return -EAGAIN;
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index 4f3c2c13a225..147481bf680c 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -165,7 +165,7 @@ static void _nbu2ss_create_ep0_packet(struct nbu2ss_udc *udc,
udc->ep0_req.req.buf = p_buf;
udc->ep0_req.req.length = length;
udc->ep0_req.req.dma = 0;
- udc->ep0_req.req.zero = TRUE;
+ udc->ep0_req.req.zero = true;
udc->ep0_req.req.complete = _nbu2ss_ep0_complete;
udc->ep0_req.req.status = -EINPROGRESS;
udc->ep0_req.req.context = udc;
@@ -668,7 +668,7 @@ static int _nbu2ss_ep0_in_transfer(struct nbu2ss_udc *udc,
if ((req->req.actual % EP0_PACKETSIZE) == 0) {
if (req->zero) {
req->zero = false;
- EP0_send_NULL(udc, FALSE);
+ EP0_send_NULL(udc, false);
return 1;
}
}
@@ -695,7 +695,7 @@ static int _nbu2ss_ep0_in_transfer(struct nbu2ss_udc *udc,
i_remain_size -= result;
if (i_remain_size == 0) {
- EP0_send_NULL(udc, FALSE);
+ EP0_send_NULL(udc, false);
return result;
}
@@ -754,7 +754,7 @@ static int _nbu2ss_ep0_out_transfer(struct nbu2ss_udc *udc,
if ((req->req.actual % EP0_PACKETSIZE) == 0) {
if (req->zero) {
req->zero = false;
- EP0_receive_NULL(udc, FALSE);
+ EP0_receive_NULL(udc, false);
return 1;
}
}
@@ -799,7 +799,7 @@ static int _nbu2ss_out_dma(struct nbu2ss_udc *udc, struct nbu2ss_req *req,
if (req->dma_flag)
return 1; /* DMA is forwarded */
- req->dma_flag = TRUE;
+ req->dma_flag = true;
p_buffer = req->req.dma;
p_buffer += req->req.actual;
@@ -997,7 +997,7 @@ static int _nbu2ss_in_dma(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep,
if (req->req.actual == 0)
_nbu2ss_dma_map_single(udc, ep, req, USB_DIR_IN);
#endif
- req->dma_flag = TRUE;
+ req->dma_flag = true;
/* MAX Packet Size */
mpkt = _nbu2ss_readl(&preg->EP_REGS[num].EP_PCKT_ADRS) & EPN_MPKT;
@@ -1166,7 +1166,7 @@ static int _nbu2ss_start_transfer(struct nbu2ss_udc *udc,
{
int nret = -EINVAL;
- req->dma_flag = FALSE;
+ req->dma_flag = false;
req->div_len = 0;
if (req->req.length == 0) {
@@ -1190,7 +1190,7 @@ static int _nbu2ss_start_transfer(struct nbu2ss_udc *udc,
break;
case EP0_IN_STATUS_PHASE:
- nret = EP0_send_NULL(udc, TRUE);
+ nret = EP0_send_NULL(udc, true);
break;
default:
@@ -1216,7 +1216,7 @@ static int _nbu2ss_start_transfer(struct nbu2ss_udc *udc,
static void _nbu2ss_restert_transfer(struct nbu2ss_ep *ep)
{
u32 length;
- bool bflag = FALSE;
+ bool bflag = false;
struct nbu2ss_req *req;
req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
@@ -1229,7 +1229,7 @@ static void _nbu2ss_restert_transfer(struct nbu2ss_ep *ep)
length &= EPN_LDATA;
if (length < ep->ep.maxpacket)
- bflag = TRUE;
+ bflag = true;
}
_nbu2ss_start_transfer(ep->udc, ep, req, bflag);
@@ -1280,7 +1280,7 @@ static void _nbu2ss_set_endpoint_stall(struct nbu2ss_udc *udc,
if (bstall) {
/* Set STALL */
- ep->halted = TRUE;
+ ep->halted = true;
if (ep_adrs & USB_DIR_IN)
data = EPN_BCLR | EPN_ISTL;
@@ -1290,7 +1290,7 @@ static void _nbu2ss_set_endpoint_stall(struct nbu2ss_udc *udc,
_nbu2ss_bitset(&preg->EP_REGS[num].EP_CONTROL, data);
} else {
/* Clear STALL */
- ep->stalled = FALSE;
+ ep->stalled = false;
if (ep_adrs & USB_DIR_IN) {
_nbu2ss_bitclr(&preg->EP_REGS[num].EP_CONTROL
, EPN_ISTL);
@@ -1305,9 +1305,9 @@ static void _nbu2ss_set_endpoint_stall(struct nbu2ss_udc *udc,
, data);
}
- ep->stalled = FALSE;
+ ep->stalled = false;
if (ep->halted) {
- ep->halted = FALSE;
+ ep->halted = false;
_nbu2ss_restert_transfer(ep);
}
}
@@ -1533,13 +1533,13 @@ static int std_req_get_status(struct nbu2ss_udc *udc)
/*-------------------------------------------------------------------------*/
static int std_req_clear_feature(struct nbu2ss_udc *udc)
{
- return _nbu2ss_req_feature(udc, FALSE);
+ return _nbu2ss_req_feature(udc, false);
}
/*-------------------------------------------------------------------------*/
static int std_req_set_feature(struct nbu2ss_udc *udc)
{
- return _nbu2ss_req_feature(udc, TRUE);
+ return _nbu2ss_req_feature(udc, true);
}
/*-------------------------------------------------------------------------*/
@@ -1601,7 +1601,7 @@ static inline void _nbu2ss_read_request_data(struct nbu2ss_udc *udc, u32 *pdata)
/*-------------------------------------------------------------------------*/
static inline int _nbu2ss_decode_request(struct nbu2ss_udc *udc)
{
- bool bcall_back = TRUE;
+ bool bcall_back = true;
int nret = -EINVAL;
struct usb_ctrlrequest *p_ctrl;
@@ -1623,22 +1623,22 @@ static inline int _nbu2ss_decode_request(struct nbu2ss_udc *udc)
switch (p_ctrl->bRequest) {
case USB_REQ_GET_STATUS:
nret = std_req_get_status(udc);
- bcall_back = FALSE;
+ bcall_back = false;
break;
case USB_REQ_CLEAR_FEATURE:
nret = std_req_clear_feature(udc);
- bcall_back = FALSE;
+ bcall_back = false;
break;
case USB_REQ_SET_FEATURE:
nret = std_req_set_feature(udc);
- bcall_back = FALSE;
+ bcall_back = false;
break;
case USB_REQ_SET_ADDRESS:
nret = std_req_set_address(udc);
- bcall_back = FALSE;
+ bcall_back = false;
break;
case USB_REQ_SET_CONFIGURATION:
@@ -1655,7 +1655,7 @@ static inline int _nbu2ss_decode_request(struct nbu2ss_udc *udc)
if (nret >= 0) {
/*--------------------------------------*/
/* Status Stage */
- nret = EP0_send_NULL(udc, TRUE);
+ nret = EP0_send_NULL(udc, true);
}
}
@@ -1688,7 +1688,7 @@ static inline int _nbu2ss_ep0_in_data_stage(struct nbu2ss_udc *udc)
nret = _nbu2ss_ep0_in_transfer(udc, req);
if (nret == 0) {
udc->ep0state = EP0_OUT_STATUS_PAHSE;
- EP0_receive_NULL(udc, TRUE);
+ EP0_receive_NULL(udc, true);
}
return 0;
@@ -1708,7 +1708,7 @@ static inline int _nbu2ss_ep0_out_data_stage(struct nbu2ss_udc *udc)
nret = _nbu2ss_ep0_out_transfer(udc, req);
if (nret == 0) {
udc->ep0state = EP0_IN_STATUS_PHASE;
- EP0_send_NULL(udc, TRUE);
+ EP0_send_NULL(udc, true);
} else if (nret < 0) {
_nbu2ss_bitset(&udc->p_regs->EP0_CONTROL, EP0_BCLR);
@@ -1817,7 +1817,7 @@ static inline void _nbu2ss_ep0_int(struct nbu2ss_udc *udc)
if (nret < 0) {
/* Send Stall */
- _nbu2ss_set_endpoint_stall(udc, 0, TRUE);
+ _nbu2ss_set_endpoint_stall(udc, 0, true);
}
}
@@ -1925,7 +1925,7 @@ static inline void _nbu2ss_epn_in_dma_int(struct nbu2ss_udc *udc,
preq->actual += req->div_len;
req->div_len = 0;
- req->dma_flag = FALSE;
+ req->dma_flag = false;
#ifdef USE_DMA
_nbu2ss_dma_unmap_single(udc, ep, req, USB_DIR_IN);
@@ -1961,7 +1961,7 @@ static inline void _nbu2ss_epn_out_dma_int(struct nbu2ss_udc *udc,
if (req->req.actual == req->req.length) {
if ((req->req.length % ep->ep.maxpacket) && !req->zero) {
req->div_len = 0;
- req->dma_flag = FALSE;
+ req->dma_flag = false;
_nbu2ss_ep_done(ep, req, 0);
return;
}
@@ -1990,7 +1990,7 @@ static inline void _nbu2ss_epn_out_dma_int(struct nbu2ss_udc *udc,
if ((req->req.actual % ep->ep.maxpacket) > 0) {
if (req->req.actual == req->div_len) {
req->div_len = 0;
- req->dma_flag = FALSE;
+ req->dma_flag = false;
_nbu2ss_ep_done(ep, req, 0);
return;
}
@@ -1998,7 +1998,7 @@ static inline void _nbu2ss_epn_out_dma_int(struct nbu2ss_udc *udc,
req->req.actual += req->div_len;
req->div_len = 0;
- req->dma_flag = FALSE;
+ req->dma_flag = false;
_nbu2ss_epn_out_int(udc, ep, req);
}
@@ -2187,7 +2187,7 @@ static int _nbu2ss_enable_controller(struct nbu2ss_udc *udc)
/* USB Interrupt Enable */
_nbu2ss_bitset(&udc->p_regs->USB_INT_ENA, USB_INT_EN_BIT);
- udc->udc_enabled = TRUE;
+ udc->udc_enabled = true;
return 0;
}
@@ -2203,7 +2203,7 @@ static void _nbu2ss_reset_controller(struct nbu2ss_udc *udc)
static void _nbu2ss_disable_controller(struct nbu2ss_udc *udc)
{
if (udc->udc_enabled) {
- udc->udc_enabled = FALSE;
+ udc->udc_enabled = false;
_nbu2ss_reset_controller(udc);
_nbu2ss_bitset(&udc->p_regs->EPCTR, (DIRPD | EPC_RST));
}
@@ -2456,8 +2456,8 @@ static int nbu2ss_ep_enable(struct usb_ep *_ep,
ep->direct = desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
ep->ep_type = ep_type;
ep->wedged = 0;
- ep->halted = FALSE;
- ep->stalled = FALSE;
+ ep->halted = false;
+ ep->stalled = false;
ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
@@ -2588,9 +2588,9 @@ static int nbu2ss_ep_queue(struct usb_ep *_ep,
#ifdef USE_DMA
if ((uintptr_t)req->req.buf & 0x3)
- req->unaligned = TRUE;
+ req->unaligned = true;
else
- req->unaligned = FALSE;
+ req->unaligned = false;
if (req->unaligned) {
if (!ep->virt_buf)
@@ -2616,7 +2616,7 @@ static int nbu2ss_ep_queue(struct usb_ep *_ep,
list_add_tail(&req->queue, &ep->queue);
if (bflag && !ep->stalled) {
- result = _nbu2ss_start_transfer(udc, ep, req, FALSE);
+ result = _nbu2ss_start_transfer(udc, ep, req, false);
if (result < 0) {
dev_err(udc->dev, " *** %s, result = %d\n", __func__,
result);
@@ -2704,12 +2704,12 @@ static int nbu2ss_ep_set_halt(struct usb_ep *_ep, int value)
ep_adrs = ep->epnum | ep->direct;
if (value == 0) {
_nbu2ss_set_endpoint_stall(udc, ep_adrs, value);
- ep->stalled = FALSE;
+ ep->stalled = false;
} else {
if (list_empty(&ep->queue))
_nbu2ss_epn_set_stall(udc, ep);
else
- ep->stalled = TRUE;
+ ep->stalled = true;
}
if (value == 0)
@@ -3094,10 +3094,8 @@ static int nbu2ss_drv_probe(struct platform_device *pdev)
return PTR_ERR(mmio_base);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get IRQ\n");
+ if (irq < 0)
return irq;
- }
status = devm_request_irq(&pdev->dev, irq, _nbu2ss_udc_irq,
0, driver_name, udc);
diff --git a/drivers/staging/emxx_udc/emxx_udc.h b/drivers/staging/emxx_udc/emxx_udc.h
index b8c3dee5626c..9c2671cb32f7 100644
--- a/drivers/staging/emxx_udc/emxx_udc.h
+++ b/drivers/staging/emxx_udc/emxx_udc.h
@@ -19,11 +19,6 @@
#define USE_DMA 1
#define USE_SUSPEND_WAIT 1
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
/*------------ Board dependence(Resource) */
#define VBUS_VALUE GPIO_VBUS
diff --git a/drivers/staging/erofs/Documentation/filesystems/erofs.txt b/drivers/staging/erofs/Documentation/filesystems/erofs.txt
deleted file mode 100644
index 74cf84ac48a3..000000000000
--- a/drivers/staging/erofs/Documentation/filesystems/erofs.txt
+++ /dev/null
@@ -1,209 +0,0 @@
-Overview
-========
-
-EROFS file-system stands for Enhanced Read-Only File System. Different
-from other read-only file systems, it aims to be designed for flexibility,
-scalability, but be kept simple and high performance.
-
-It is designed as a better filesystem solution for the following scenarios:
- - read-only storage media or
-
- - part of a fully trusted read-only solution, which means it needs to be
- immutable and bit-for-bit identical to the official golden image for
- their releases due to security and other considerations and
-
- - hope to save some extra storage space with guaranteed end-to-end performance
- by using reduced metadata and transparent file compression, especially
- for those embedded devices with limited memory (ex, smartphone);
-
-Here is the main features of EROFS:
- - Little endian on-disk design;
-
- - Currently 4KB block size (nobh) and therefore maximum 16TB address space;
-
- - Metadata & data could be mixed by design;
-
- - 2 inode versions for different requirements:
- v1 v2
- Inode metadata size: 32 bytes 64 bytes
- Max file size: 4 GB 16 EB (also limited by max. vol size)
- Max uids/gids: 65536 4294967296
- File creation time: no yes (64 + 32-bit timestamp)
- Max hardlinks: 65536 4294967296
- Metadata reserved: 4 bytes 14 bytes
-
- - Support extended attributes (xattrs) as an option;
-
- - Support xattr inline and tail-end data inline for all files;
-
- - Support POSIX.1e ACLs by using xattrs;
-
- - Support transparent file compression as an option:
- LZ4 algorithm with 4 KB fixed-output compression for high performance;
-
-The following git tree provides the file system user-space tools under
-development (ex, formatting tool mkfs.erofs):
->> git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git
-
-Bugs and patches are welcome, please kindly help us and send to the following
-linux-erofs mailing list:
->> linux-erofs mailing list <linux-erofs@lists.ozlabs.org>
-
-Note that EROFS is still working in progress as a Linux staging driver,
-Cc the staging mailing list as well is highly recommended:
->> Linux Driver Project Developer List <devel@driverdev.osuosl.org>
-
-Mount options
-=============
-
-fault_injection=%d Enable fault injection in all supported types with
- specified injection rate. Supported injection type:
- Type_Name Type_Value
- FAULT_KMALLOC 0x000000001
- FAULT_READ_IO 0x000000002
-(no)user_xattr Setup Extended User Attributes. Note: xattr is enabled
- by default if CONFIG_EROFS_FS_XATTR is selected.
-(no)acl Setup POSIX Access Control List. Note: acl is enabled
- by default if CONFIG_EROFS_FS_POSIX_ACL is selected.
-
-On-disk details
-===============
-
-Summary
--------
-Different from other read-only file systems, an EROFS volume is designed
-to be as simple as possible:
-
- |-> aligned with the block size
- ____________________________________________________________
- | |SB| | ... | Metadata | ... | Data | Metadata | ... | Data |
- |_|__|_|_____|__________|_____|______|__________|_____|______|
- 0 +1K
-
-All data areas should be aligned with the block size, but metadata areas
-may not. All metadatas can be now observed in two different spaces (views):
- 1. Inode metadata space
- Each valid inode should be aligned with an inode slot, which is a fixed
- value (32 bytes) and designed to be kept in line with v1 inode size.
-
- Each inode can be directly found with the following formula:
- inode offset = meta_blkaddr * block_size + 32 * nid
-
- |-> aligned with 8B
- |-> followed closely
- + meta_blkaddr blocks |-> another slot
- _____________________________________________________________________
- | ... | inode | xattrs | extents | data inline | ... | inode ...
- |________|_______|(optional)|(optional)|__(optional)_|_____|__________
- |-> aligned with the inode slot size
- . .
- . .
- . .
- . .
- . .
- . .
- .____________________________________________________|-> aligned with 4B
- | xattr_ibody_header | shared xattrs | inline xattrs |
- |____________________|_______________|_______________|
- |-> 12 bytes <-|->x * 4 bytes<-| .
- . . .
- . . .
- . . .
- ._______________________________.______________________.
- | id | id | id | id | ... | id | ent | ... | ent| ... |
- |____|____|____|____|______|____|_____|_____|____|_____|
- |-> aligned with 4B
- |-> aligned with 4B
-
- Inode could be 32 or 64 bytes, which can be distinguished from a common
- field which all inode versions have -- i_advise:
-
- __________________ __________________
- | i_advise | | i_advise |
- |__________________| |__________________|
- | ... | | ... |
- | | | |
- |__________________| 32 bytes | |
- | |
- |__________________| 64 bytes
-
- Xattrs, extents, data inline are followed by the corresponding inode with
- proper alignes, and they could be optional for different data mappings,
- _currently_ there are totally 3 valid data mappings supported:
-
- 1) flat file data without data inline (no extent);
- 2) fixed-output size data compression (must have extents);
- 3) flat file data with tail-end data inline (no extent);
-
- The size of the optional xattrs is indicated by i_xattr_count in inode
- header. Large xattrs or xattrs shared by many different files can be
- stored in shared xattrs metadata rather than inlined right after inode.
-
- 2. Shared xattrs metadata space
- Shared xattrs space is similar to the above inode space, started with
- a specific block indicated by xattr_blkaddr, organized one by one with
- proper align.
-
- Each share xattr can also be directly found by the following formula:
- xattr offset = xattr_blkaddr * block_size + 4 * xattr_id
-
- |-> aligned by 4 bytes
- + xattr_blkaddr blocks |-> aligned with 4 bytes
- _________________________________________________________________________
- | ... | xattr_entry | xattr data | ... | xattr_entry | xattr data ...
- |________|_____________|_____________|_____|______________|_______________
-
-Directories
------------
-All directories are now organized in a compact on-disk format. Note that
-each directory block is divided into index and name areas in order to support
-random file lookup, and all directory entries are _strictly_ recorded in
-alphabetical order in order to support improved prefix binary search
-algorithm (could refer to the related source code).
-
- ___________________________
- / |
- / ______________|________________
- / / | nameoff1 | nameoffN-1
- ____________.______________._______________v________________v__________
-| dirent | dirent | ... | dirent | filename | filename | ... | filename |
-|___.0___|____1___|_____|___N-1__|____0_____|____1_____|_____|___N-1____|
- \ ^
- \ | * could have
- \ | trailing '\0'
- \________________________| nameoff0
-
- Directory block
-
-Note that apart from the offset of the first filename, nameoff0 also indicates
-the total number of directory entries in this block since it is no need to
-introduce another on-disk field at all.
-
-Compression
------------
-Currently, EROFS supports 4KB fixed-output clustersize transparent file
-compression, as illustrated below:
-
- |---- Variant-Length Extent ----|-------- VLE --------|----- VLE -----
- clusterofs clusterofs clusterofs
- | | | logical data
-_________v_______________________________v_____________________v_______________
-... | . | | . | | . | ...
-____|____.________|_____________|________.____|_____________|__.__________|____
- |-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|
- size size size size size
- . . . .
- . . . .
- . . . .
- _______._____________._____________._____________._____________________
- ... | | | | ... physical data
- _______|_____________|_____________|_____________|_____________________
- |-> cluster <-|-> cluster <-|-> cluster <-|
- size size size
-
-Currently each on-disk physical cluster can contain 4KB (un)compressed data
-at most. For each logical cluster, there is a corresponding on-disk index to
-describe its cluster type, physical cluster address, etc.
-
-See "struct z_erofs_vle_decompressed_index" in erofs_fs.h for more details.
-
diff --git a/drivers/staging/erofs/Kconfig b/drivers/staging/erofs/Kconfig
deleted file mode 100644
index d04b798a8efb..000000000000
--- a/drivers/staging/erofs/Kconfig
+++ /dev/null
@@ -1,151 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-config EROFS_FS
- tristate "EROFS filesystem support"
- depends on BLOCK
- help
- EROFS(Enhanced Read-Only File System) is a lightweight
- read-only file system with modern designs (eg. page-sized
- blocks, inline xattrs/data, etc.) for scenarios which need
- high-performance read-only requirements, eg. firmwares in
- mobile phone or LIVECDs.
-
- It also provides VLE compression support, focusing on
- random read improvements, keeping relatively lower
- compression ratios, which is useful for high-performance
- devices with limited memory and ROM space.
-
- If unsure, say N.
-
-config EROFS_FS_DEBUG
- bool "EROFS debugging feature"
- depends on EROFS_FS
- help
- Print EROFS debugging messages and enable more BUG_ONs
- which check the filesystem consistency aggressively.
-
- For daily use, say N.
-
-config EROFS_FS_XATTR
- bool "EROFS extended attributes"
- depends on EROFS_FS
- default y
- help
- Extended attributes are name:value pairs associated with inodes by
- the kernel or by users (see the attr(5) manual page, or visit
- <http://acl.bestbits.at/> for details).
-
- If unsure, say N.
-
-config EROFS_FS_POSIX_ACL
- bool "EROFS Access Control Lists"
- depends on EROFS_FS_XATTR
- select FS_POSIX_ACL
- default y
- help
- Posix Access Control Lists (ACLs) support permissions for users and
- groups beyond the owner/group/world scheme.
-
- To learn more about Access Control Lists, visit the POSIX ACLs for
- Linux website <http://acl.bestbits.at/>.
-
- If you don't know what Access Control Lists are, say N.
-
-config EROFS_FS_SECURITY
- bool "EROFS Security Labels"
- depends on EROFS_FS_XATTR
- help
- Security labels provide an access control facility to support Linux
- Security Models (LSMs) accepted by AppArmor, SELinux, Smack and TOMOYO
- Linux. This option enables an extended attribute handler for file
- security labels in the erofs filesystem, so that it requires enabling
- the extended attribute support in advance.
-
- If you are not using a security module, say N.
-
-config EROFS_FS_USE_VM_MAP_RAM
- bool "EROFS VM_MAP_RAM Support"
- depends on EROFS_FS
- help
- use vm_map_ram/vm_unmap_ram instead of vmap/vunmap.
-
- If you don't know what these are, say N.
-
-config EROFS_FAULT_INJECTION
- bool "EROFS fault injection facility"
- depends on EROFS_FS
- help
- Test EROFS to inject faults such as ENOMEM, EIO, and so on.
- If unsure, say N.
-
-config EROFS_FS_IO_MAX_RETRIES
- int "EROFS IO Maximum Retries"
- depends on EROFS_FS
- default "5"
- help
- Maximum retry count of IO Errors.
-
- If unsure, leave the default value (5 retries, 6 IOs at most).
-
-config EROFS_FS_ZIP
- bool "EROFS Data Compresssion Support"
- depends on EROFS_FS
- select LZ4_DECOMPRESS
- help
- Currently we support LZ4 VLE Compression only.
- Play at your own risk.
-
- If you don't want to use compression feature, say N.
-
-config EROFS_FS_CLUSTER_PAGE_LIMIT
- int "EROFS Cluster Pages Hard Limit"
- depends on EROFS_FS_ZIP
- range 1 256
- default "1"
- help
- Indicates VLE compressed pages hard limit of a
- compressed cluster.
-
- For example, if files of a image are compressed
- into 8k-unit, the hard limit should not be less
- than 2. Otherwise, the image cannot be mounted
- correctly on this kernel.
-
-choice
- prompt "EROFS VLE Data Decompression mode"
- depends on EROFS_FS_ZIP
- default EROFS_FS_ZIP_CACHE_BIPOLAR
- help
- EROFS supports three options for VLE decompression.
- "In-place Decompression Only" consumes the minimum memory
- with lowest random read.
-
- "Bipolar Cached Decompression" consumes the maximum memory
- with highest random read.
-
- If unsure, select "Bipolar Cached Decompression"
-
-config EROFS_FS_ZIP_NO_CACHE
- bool "In-place Decompression Only"
- help
- Read compressed data into page cache and do in-place
- decompression directly.
-
-config EROFS_FS_ZIP_CACHE_UNIPOLAR
- bool "Unipolar Cached Decompression"
- help
- For each request, it caches the last compressed page
- for further reading.
- It still decompresses in place for the rest compressed pages.
-
-config EROFS_FS_ZIP_CACHE_BIPOLAR
- bool "Bipolar Cached Decompression"
- help
- For each request, it caches the both end compressed pages
- for further reading.
- It still decompresses in place for the rest compressed pages.
-
- Recommended for performance priority.
-
-endchoice
-
diff --git a/drivers/staging/erofs/Makefile b/drivers/staging/erofs/Makefile
deleted file mode 100644
index e704d9e51514..000000000000
--- a/drivers/staging/erofs/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-EROFS_VERSION = "1.0pre1"
-
-ccflags-y += -DEROFS_VERSION=\"$(EROFS_VERSION)\"
-
-obj-$(CONFIG_EROFS_FS) += erofs.o
-# staging requirement: to be self-contained in its own directory
-ccflags-y += -I $(srctree)/$(src)/include
-erofs-objs := super.o inode.o data.o namei.o dir.o utils.o
-erofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o
-erofs-$(CONFIG_EROFS_FS_ZIP) += unzip_vle.o zmap.o decompressor.o
-
diff --git a/drivers/staging/erofs/TODO b/drivers/staging/erofs/TODO
deleted file mode 100644
index a8608b2f72bd..000000000000
--- a/drivers/staging/erofs/TODO
+++ /dev/null
@@ -1,46 +0,0 @@
-
-EROFS is still working in progress, thus it is not suitable
-for all productive uses. play at your own risk :)
-
-TODO List:
- - add the missing error handling code
- (mainly existed in xattr and decompression submodules);
-
- - finalize erofs ondisk format design (which means that
- minor on-disk revisions could happen later);
-
- - documentation and detailed technical analysis;
-
- - general code review and clean up
- (including confusing variable names and code snippets);
-
- - support larger compressed clustersizes for selection
- (currently erofs only works as expected with the page-sized
- compressed cluster configuration, usually 4KB);
-
- - support more lossless data compression algorithms
- in addition to LZ4 algorithms in VLE approach;
-
- - data deduplication and other useful features.
-
-The following git tree provides the file system user-space
-tools under development (ex, formatting tool mkfs.erofs):
->> git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git
-
-The open-source development of erofs-utils is at the early stage.
-Contact the original author Li Guifu <bluce.liguifu@huawei.com> and
-the co-maintainer Fang Wei <fangwei1@huawei.com> for the latest news
-and more details.
-
-Code, suggestions, etc, are welcome. Please feel free to
-ask and send patches,
-
-To:
- linux-erofs mailing list <linux-erofs@lists.ozlabs.org>
- Gao Xiang <gaoxiang25@huawei.com>
- Chao Yu <yuchao0@huawei.com>
-
-Cc: (for linux-kernel upstream patches)
- Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- linux-staging mailing list <devel@driverdev.osuosl.org>
-
diff --git a/drivers/staging/erofs/compress.h b/drivers/staging/erofs/compress.h
deleted file mode 100644
index c43aa3374d28..000000000000
--- a/drivers/staging/erofs/compress.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/drivers/staging/erofs/compress.h
- *
- * Copyright (C) 2019 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- */
-#ifndef __EROFS_FS_COMPRESS_H
-#define __EROFS_FS_COMPRESS_H
-
-#include "internal.h"
-
-enum {
- Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX,
- Z_EROFS_COMPRESSION_RUNTIME_MAX
-};
-
-struct z_erofs_decompress_req {
- struct super_block *sb;
- struct page **in, **out;
-
- unsigned short pageofs_out;
- unsigned int inputsize, outputsize;
-
- /* indicate the algorithm will be used for decompression */
- unsigned int alg;
- bool inplace_io, partial_decoding;
-};
-
-/*
- * - 0x5A110C8D ('sallocated', Z_EROFS_MAPPING_STAGING) -
- * used to mark temporary allocated pages from other
- * file/cached pages and NULL mapping pages.
- */
-#define Z_EROFS_MAPPING_STAGING ((void *)0x5A110C8D)
-
-/* check if a page is marked as staging */
-static inline bool z_erofs_page_is_staging(struct page *page)
-{
- return page->mapping == Z_EROFS_MAPPING_STAGING;
-}
-
-static inline bool z_erofs_put_stagingpage(struct list_head *pagepool,
- struct page *page)
-{
- if (!z_erofs_page_is_staging(page))
- return false;
-
- /* staging pages should not be used by others at the same time */
- if (page_ref_count(page) > 1)
- put_page(page);
- else
- list_add(&page->lru, pagepool);
- return true;
-}
-
-int z_erofs_decompress(struct z_erofs_decompress_req *rq,
- struct list_head *pagepool);
-
-#endif
-
diff --git a/drivers/staging/erofs/data.c b/drivers/staging/erofs/data.c
deleted file mode 100644
index cc31c3e5984c..000000000000
--- a/drivers/staging/erofs/data.c
+++ /dev/null
@@ -1,400 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/data.c
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#include "internal.h"
-#include <linux/prefetch.h>
-
-#include <trace/events/erofs.h>
-
-static inline void read_endio(struct bio *bio)
-{
- struct super_block *const sb = bio->bi_private;
- struct bio_vec *bvec;
- blk_status_t err = bio->bi_status;
- struct bvec_iter_all iter_all;
-
- if (time_to_inject(EROFS_SB(sb), FAULT_READ_IO)) {
- erofs_show_injection_info(FAULT_READ_IO);
- err = BLK_STS_IOERR;
- }
-
- bio_for_each_segment_all(bvec, bio, iter_all) {
- struct page *page = bvec->bv_page;
-
- /* page is already locked */
- DBG_BUGON(PageUptodate(page));
-
- if (unlikely(err))
- SetPageError(page);
- else
- SetPageUptodate(page);
-
- unlock_page(page);
- /* page could be reclaimed now */
- }
- bio_put(bio);
-}
-
-/* prio -- true is used for dir */
-struct page *__erofs_get_meta_page(struct super_block *sb,
- erofs_blk_t blkaddr, bool prio, bool nofail)
-{
- struct inode *const bd_inode = sb->s_bdev->bd_inode;
- struct address_space *const mapping = bd_inode->i_mapping;
- /* prefer retrying in the allocator to blindly looping below */
- const gfp_t gfp = mapping_gfp_constraint(mapping, ~__GFP_FS) |
- (nofail ? __GFP_NOFAIL : 0);
- unsigned int io_retries = nofail ? EROFS_IO_MAX_RETRIES_NOFAIL : 0;
- struct page *page;
- int err;
-
-repeat:
- page = find_or_create_page(mapping, blkaddr, gfp);
- if (unlikely(!page)) {
- DBG_BUGON(nofail);
- return ERR_PTR(-ENOMEM);
- }
- DBG_BUGON(!PageLocked(page));
-
- if (!PageUptodate(page)) {
- struct bio *bio;
-
- bio = erofs_grab_bio(sb, blkaddr, 1, sb, read_endio, nofail);
- if (IS_ERR(bio)) {
- DBG_BUGON(nofail);
- err = PTR_ERR(bio);
- goto err_out;
- }
-
- err = bio_add_page(bio, page, PAGE_SIZE, 0);
- if (unlikely(err != PAGE_SIZE)) {
- err = -EFAULT;
- goto err_out;
- }
-
- __submit_bio(bio, REQ_OP_READ,
- REQ_META | (prio ? REQ_PRIO : 0));
-
- lock_page(page);
-
- /* this page has been truncated by others */
- if (unlikely(page->mapping != mapping)) {
-unlock_repeat:
- unlock_page(page);
- put_page(page);
- goto repeat;
- }
-
- /* more likely a read error */
- if (unlikely(!PageUptodate(page))) {
- if (io_retries) {
- --io_retries;
- goto unlock_repeat;
- }
- err = -EIO;
- goto err_out;
- }
- }
- return page;
-
-err_out:
- unlock_page(page);
- put_page(page);
- return ERR_PTR(err);
-}
-
-static int erofs_map_blocks_flatmode(struct inode *inode,
- struct erofs_map_blocks *map,
- int flags)
-{
- int err = 0;
- erofs_blk_t nblocks, lastblk;
- u64 offset = map->m_la;
- struct erofs_vnode *vi = EROFS_V(inode);
-
- trace_erofs_map_blocks_flatmode_enter(inode, map, flags);
-
- nblocks = DIV_ROUND_UP(inode->i_size, PAGE_SIZE);
- lastblk = nblocks - is_inode_flat_inline(inode);
-
- if (unlikely(offset >= inode->i_size)) {
- /* leave out-of-bound access unmapped */
- map->m_flags = 0;
- map->m_plen = 0;
- goto out;
- }
-
- /* there is no hole in flatmode */
- map->m_flags = EROFS_MAP_MAPPED;
-
- if (offset < blknr_to_addr(lastblk)) {
- map->m_pa = blknr_to_addr(vi->raw_blkaddr) + map->m_la;
- map->m_plen = blknr_to_addr(lastblk) - offset;
- } else if (is_inode_flat_inline(inode)) {
- /* 2 - inode inline B: inode, [xattrs], inline last blk... */
- struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
-
- map->m_pa = iloc(sbi, vi->nid) + vi->inode_isize +
- vi->xattr_isize + erofs_blkoff(map->m_la);
- map->m_plen = inode->i_size - offset;
-
- /* inline data should locate in one meta block */
- if (erofs_blkoff(map->m_pa) + map->m_plen > PAGE_SIZE) {
- DBG_BUGON(1);
- err = -EIO;
- goto err_out;
- }
-
- map->m_flags |= EROFS_MAP_META;
- } else {
- errln("internal error @ nid: %llu (size %llu), m_la 0x%llx",
- vi->nid, inode->i_size, map->m_la);
- DBG_BUGON(1);
- err = -EIO;
- goto err_out;
- }
-
-out:
- map->m_llen = map->m_plen;
-
-err_out:
- trace_erofs_map_blocks_flatmode_exit(inode, map, flags, 0);
- return err;
-}
-
-int erofs_map_blocks(struct inode *inode,
- struct erofs_map_blocks *map, int flags)
-{
- if (unlikely(is_inode_layout_compression(inode))) {
- int err = z_erofs_map_blocks_iter(inode, map, flags);
-
- if (map->mpage) {
- put_page(map->mpage);
- map->mpage = NULL;
- }
- return err;
- }
- return erofs_map_blocks_flatmode(inode, map, flags);
-}
-
-static inline struct bio *erofs_read_raw_page(struct bio *bio,
- struct address_space *mapping,
- struct page *page,
- erofs_off_t *last_block,
- unsigned int nblocks,
- bool ra)
-{
- struct inode *const inode = mapping->host;
- struct super_block *const sb = inode->i_sb;
- erofs_off_t current_block = (erofs_off_t)page->index;
- int err;
-
- DBG_BUGON(!nblocks);
-
- if (PageUptodate(page)) {
- err = 0;
- goto has_updated;
- }
-
- if (cleancache_get_page(page) == 0) {
- err = 0;
- SetPageUptodate(page);
- goto has_updated;
- }
-
- /* note that for readpage case, bio also equals to NULL */
- if (bio &&
- /* not continuous */
- *last_block + 1 != current_block) {
-submit_bio_retry:
- __submit_bio(bio, REQ_OP_READ, 0);
- bio = NULL;
- }
-
- if (!bio) {
- struct erofs_map_blocks map = {
- .m_la = blknr_to_addr(current_block),
- };
- erofs_blk_t blknr;
- unsigned int blkoff;
-
- err = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW);
- if (unlikely(err))
- goto err_out;
-
- /* zero out the holed page */
- if (unlikely(!(map.m_flags & EROFS_MAP_MAPPED))) {
- zero_user_segment(page, 0, PAGE_SIZE);
- SetPageUptodate(page);
-
- /* imply err = 0, see erofs_map_blocks */
- goto has_updated;
- }
-
- /* for RAW access mode, m_plen must be equal to m_llen */
- DBG_BUGON(map.m_plen != map.m_llen);
-
- blknr = erofs_blknr(map.m_pa);
- blkoff = erofs_blkoff(map.m_pa);
-
- /* deal with inline page */
- if (map.m_flags & EROFS_MAP_META) {
- void *vsrc, *vto;
- struct page *ipage;
-
- DBG_BUGON(map.m_plen > PAGE_SIZE);
-
- ipage = erofs_get_meta_page(inode->i_sb, blknr, 0);
-
- if (IS_ERR(ipage)) {
- err = PTR_ERR(ipage);
- goto err_out;
- }
-
- vsrc = kmap_atomic(ipage);
- vto = kmap_atomic(page);
- memcpy(vto, vsrc + blkoff, map.m_plen);
- memset(vto + map.m_plen, 0, PAGE_SIZE - map.m_plen);
- kunmap_atomic(vto);
- kunmap_atomic(vsrc);
- flush_dcache_page(page);
-
- SetPageUptodate(page);
- /* TODO: could we unlock the page earlier? */
- unlock_page(ipage);
- put_page(ipage);
-
- /* imply err = 0, see erofs_map_blocks */
- goto has_updated;
- }
-
- /* pa must be block-aligned for raw reading */
- DBG_BUGON(erofs_blkoff(map.m_pa));
-
- /* max # of continuous pages */
- if (nblocks > DIV_ROUND_UP(map.m_plen, PAGE_SIZE))
- nblocks = DIV_ROUND_UP(map.m_plen, PAGE_SIZE);
- if (nblocks > BIO_MAX_PAGES)
- nblocks = BIO_MAX_PAGES;
-
- bio = erofs_grab_bio(sb, blknr, nblocks, sb,
- read_endio, false);
- if (IS_ERR(bio)) {
- err = PTR_ERR(bio);
- bio = NULL;
- goto err_out;
- }
- }
-
- err = bio_add_page(bio, page, PAGE_SIZE, 0);
- /* out of the extent or bio is full */
- if (err < PAGE_SIZE)
- goto submit_bio_retry;
-
- *last_block = current_block;
-
- /* shift in advance in case of it followed by too many gaps */
- if (bio->bi_iter.bi_size >= bio->bi_max_vecs * PAGE_SIZE) {
- /* err should reassign to 0 after submitting */
- err = 0;
- goto submit_bio_out;
- }
-
- return bio;
-
-err_out:
- /* for sync reading, set page error immediately */
- if (!ra) {
- SetPageError(page);
- ClearPageUptodate(page);
- }
-has_updated:
- unlock_page(page);
-
- /* if updated manually, continuous pages has a gap */
- if (bio)
-submit_bio_out:
- __submit_bio(bio, REQ_OP_READ, 0);
-
- return unlikely(err) ? ERR_PTR(err) : NULL;
-}
-
-/*
- * since we dont have write or truncate flows, so no inode
- * locking needs to be held at the moment.
- */
-static int erofs_raw_access_readpage(struct file *file, struct page *page)
-{
- erofs_off_t last_block;
- struct bio *bio;
-
- trace_erofs_readpage(page, true);
-
- bio = erofs_read_raw_page(NULL, page->mapping,
- page, &last_block, 1, false);
-
- if (IS_ERR(bio))
- return PTR_ERR(bio);
-
- DBG_BUGON(bio); /* since we have only one bio -- must be NULL */
- return 0;
-}
-
-static int erofs_raw_access_readpages(struct file *filp,
- struct address_space *mapping,
- struct list_head *pages,
- unsigned int nr_pages)
-{
- erofs_off_t last_block;
- struct bio *bio = NULL;
- gfp_t gfp = readahead_gfp_mask(mapping);
- struct page *page = list_last_entry(pages, struct page, lru);
-
- trace_erofs_readpages(mapping->host, page, nr_pages, true);
-
- for (; nr_pages; --nr_pages) {
- page = list_entry(pages->prev, struct page, lru);
-
- prefetchw(&page->flags);
- list_del(&page->lru);
-
- if (!add_to_page_cache_lru(page, mapping, page->index, gfp)) {
- bio = erofs_read_raw_page(bio, mapping, page,
- &last_block, nr_pages, true);
-
- /* all the page errors are ignored when readahead */
- if (IS_ERR(bio)) {
- pr_err("%s, readahead error at page %lu of nid %llu\n",
- __func__, page->index,
- EROFS_V(mapping->host)->nid);
-
- bio = NULL;
- }
- }
-
- /* pages could still be locked */
- put_page(page);
- }
- DBG_BUGON(!list_empty(pages));
-
- /* the rare case (end in gaps) */
- if (unlikely(bio))
- __submit_bio(bio, REQ_OP_READ, 0);
- return 0;
-}
-
-/* for uncompressed (aligned) files and raw access for other files */
-const struct address_space_operations erofs_raw_access_aops = {
- .readpage = erofs_raw_access_readpage,
- .readpages = erofs_raw_access_readpages,
-};
-
diff --git a/drivers/staging/erofs/decompressor.c b/drivers/staging/erofs/decompressor.c
deleted file mode 100644
index 1fb0abb98dff..000000000000
--- a/drivers/staging/erofs/decompressor.c
+++ /dev/null
@@ -1,335 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/decompressor.c
- *
- * Copyright (C) 2019 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- */
-#include "compress.h"
-#include <linux/lz4.h>
-
-#ifndef LZ4_DISTANCE_MAX /* history window size */
-#define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
-#endif
-
-#define LZ4_MAX_DISTANCE_PAGES (DIV_ROUND_UP(LZ4_DISTANCE_MAX, PAGE_SIZE) + 1)
-#ifndef LZ4_DECOMPRESS_INPLACE_MARGIN
-#define LZ4_DECOMPRESS_INPLACE_MARGIN(srcsize) (((srcsize) >> 8) + 32)
-#endif
-
-struct z_erofs_decompressor {
- /*
- * if destpages have sparsed pages, fill them with bounce pages.
- * it also check whether destpages indicate continuous physical memory.
- */
- int (*prepare_destpages)(struct z_erofs_decompress_req *rq,
- struct list_head *pagepool);
- int (*decompress)(struct z_erofs_decompress_req *rq, u8 *out);
- char *name;
-};
-
-static int lz4_prepare_destpages(struct z_erofs_decompress_req *rq,
- struct list_head *pagepool)
-{
- const unsigned int nr =
- PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
- struct page *availables[LZ4_MAX_DISTANCE_PAGES] = { NULL };
- unsigned long bounced[DIV_ROUND_UP(LZ4_MAX_DISTANCE_PAGES,
- BITS_PER_LONG)] = { 0 };
- void *kaddr = NULL;
- unsigned int i, j, top;
-
- top = 0;
- for (i = j = 0; i < nr; ++i, ++j) {
- struct page *const page = rq->out[i];
- struct page *victim;
-
- if (j >= LZ4_MAX_DISTANCE_PAGES)
- j = 0;
-
- /* 'valid' bounced can only be tested after a complete round */
- if (test_bit(j, bounced)) {
- DBG_BUGON(i < LZ4_MAX_DISTANCE_PAGES);
- DBG_BUGON(top >= LZ4_MAX_DISTANCE_PAGES);
- availables[top++] = rq->out[i - LZ4_MAX_DISTANCE_PAGES];
- }
-
- if (page) {
- __clear_bit(j, bounced);
- if (kaddr) {
- if (kaddr + PAGE_SIZE == page_address(page))
- kaddr += PAGE_SIZE;
- else
- kaddr = NULL;
- } else if (!i) {
- kaddr = page_address(page);
- }
- continue;
- }
- kaddr = NULL;
- __set_bit(j, bounced);
-
- if (top) {
- victim = availables[--top];
- get_page(victim);
- } else {
- if (!list_empty(pagepool)) {
- victim = lru_to_page(pagepool);
- list_del(&victim->lru);
- DBG_BUGON(page_ref_count(victim) != 1);
- } else {
- victim = alloc_pages(GFP_KERNEL, 0);
- if (!victim)
- return -ENOMEM;
- }
- victim->mapping = Z_EROFS_MAPPING_STAGING;
- }
- rq->out[i] = victim;
- }
- return kaddr ? 1 : 0;
-}
-
-static void *generic_copy_inplace_data(struct z_erofs_decompress_req *rq,
- u8 *src, unsigned int pageofs_in)
-{
- /*
- * if in-place decompression is ongoing, those decompressed
- * pages should be copied in order to avoid being overlapped.
- */
- struct page **in = rq->in;
- u8 *const tmp = erofs_get_pcpubuf(0);
- u8 *tmpp = tmp;
- unsigned int inlen = rq->inputsize - pageofs_in;
- unsigned int count = min_t(uint, inlen, PAGE_SIZE - pageofs_in);
-
- while (tmpp < tmp + inlen) {
- if (!src)
- src = kmap_atomic(*in);
- memcpy(tmpp, src + pageofs_in, count);
- kunmap_atomic(src);
- src = NULL;
- tmpp += count;
- pageofs_in = 0;
- count = PAGE_SIZE;
- ++in;
- }
- return tmp;
-}
-
-static int lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out)
-{
- unsigned int inputmargin, inlen;
- u8 *src;
- bool copied, support_0padding;
- int ret;
-
- if (rq->inputsize > PAGE_SIZE)
- return -ENOTSUPP;
-
- src = kmap_atomic(*rq->in);
- inputmargin = 0;
- support_0padding = false;
-
- /* decompression inplace is only safe when 0padding is enabled */
- if (EROFS_SB(rq->sb)->requirements & EROFS_REQUIREMENT_LZ4_0PADDING) {
- support_0padding = true;
-
- while (!src[inputmargin & ~PAGE_MASK])
- if (!(++inputmargin & ~PAGE_MASK))
- break;
-
- if (inputmargin >= rq->inputsize) {
- kunmap_atomic(src);
- return -EIO;
- }
- }
-
- copied = false;
- inlen = rq->inputsize - inputmargin;
- if (rq->inplace_io) {
- const uint oend = (rq->pageofs_out +
- rq->outputsize) & ~PAGE_MASK;
- const uint nr = PAGE_ALIGN(rq->pageofs_out +
- rq->outputsize) >> PAGE_SHIFT;
-
- if (rq->partial_decoding || !support_0padding ||
- rq->out[nr - 1] != rq->in[0] ||
- rq->inputsize - oend <
- LZ4_DECOMPRESS_INPLACE_MARGIN(inlen)) {
- src = generic_copy_inplace_data(rq, src, inputmargin);
- inputmargin = 0;
- copied = true;
- }
- }
-
- ret = LZ4_decompress_safe_partial(src + inputmargin, out,
- inlen, rq->outputsize,
- rq->outputsize);
- if (ret < 0) {
- errln("%s, failed to decompress, in[%p, %u, %u] out[%p, %u]",
- __func__, src + inputmargin, inlen, inputmargin,
- out, rq->outputsize);
- WARN_ON(1);
- print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET,
- 16, 1, src + inputmargin, inlen, true);
- print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET,
- 16, 1, out, rq->outputsize, true);
- ret = -EIO;
- }
-
- if (copied)
- erofs_put_pcpubuf(src);
- else
- kunmap_atomic(src);
- return ret;
-}
-
-static struct z_erofs_decompressor decompressors[] = {
- [Z_EROFS_COMPRESSION_SHIFTED] = {
- .name = "shifted"
- },
- [Z_EROFS_COMPRESSION_LZ4] = {
- .prepare_destpages = lz4_prepare_destpages,
- .decompress = lz4_decompress,
- .name = "lz4"
- },
-};
-
-static void copy_from_pcpubuf(struct page **out, const char *dst,
- unsigned short pageofs_out,
- unsigned int outputsize)
-{
- const char *end = dst + outputsize;
- const unsigned int righthalf = PAGE_SIZE - pageofs_out;
- const char *cur = dst - pageofs_out;
-
- while (cur < end) {
- struct page *const page = *out++;
-
- if (page) {
- char *buf = kmap_atomic(page);
-
- if (cur >= dst) {
- memcpy(buf, cur, min_t(uint, PAGE_SIZE,
- end - cur));
- } else {
- memcpy(buf + pageofs_out, cur + pageofs_out,
- min_t(uint, righthalf, end - cur));
- }
- kunmap_atomic(buf);
- }
- cur += PAGE_SIZE;
- }
-}
-
-static int decompress_generic(struct z_erofs_decompress_req *rq,
- struct list_head *pagepool)
-{
- const unsigned int nrpages_out =
- PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
- const struct z_erofs_decompressor *alg = decompressors + rq->alg;
- unsigned int dst_maptype;
- void *dst;
- int ret;
-
- if (nrpages_out == 1 && !rq->inplace_io) {
- DBG_BUGON(!*rq->out);
- dst = kmap_atomic(*rq->out);
- dst_maptype = 0;
- goto dstmap_out;
- }
-
- /*
- * For the case of small output size (especially much less
- * than PAGE_SIZE), memcpy the decompressed data rather than
- * compressed data is preferred.
- */
- if (rq->outputsize <= PAGE_SIZE * 7 / 8) {
- dst = erofs_get_pcpubuf(0);
- if (IS_ERR(dst))
- return PTR_ERR(dst);
-
- rq->inplace_io = false;
- ret = alg->decompress(rq, dst);
- if (!ret)
- copy_from_pcpubuf(rq->out, dst, rq->pageofs_out,
- rq->outputsize);
-
- erofs_put_pcpubuf(dst);
- return ret;
- }
-
- ret = alg->prepare_destpages(rq, pagepool);
- if (ret < 0) {
- return ret;
- } else if (ret) {
- dst = page_address(*rq->out);
- dst_maptype = 1;
- goto dstmap_out;
- }
-
- dst = erofs_vmap(rq->out, nrpages_out);
- if (!dst)
- return -ENOMEM;
- dst_maptype = 2;
-
-dstmap_out:
- ret = alg->decompress(rq, dst + rq->pageofs_out);
-
- if (!dst_maptype)
- kunmap_atomic(dst);
- else if (dst_maptype == 2)
- erofs_vunmap(dst, nrpages_out);
- return ret;
-}
-
-static int shifted_decompress(const struct z_erofs_decompress_req *rq,
- struct list_head *pagepool)
-{
- const unsigned int nrpages_out =
- PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
- const unsigned int righthalf = PAGE_SIZE - rq->pageofs_out;
- unsigned char *src, *dst;
-
- if (nrpages_out > 2) {
- DBG_BUGON(1);
- return -EIO;
- }
-
- if (rq->out[0] == *rq->in) {
- DBG_BUGON(nrpages_out != 1);
- return 0;
- }
-
- src = kmap_atomic(*rq->in);
- if (!rq->out[0]) {
- dst = NULL;
- } else {
- dst = kmap_atomic(rq->out[0]);
- memcpy(dst + rq->pageofs_out, src, righthalf);
- }
-
- if (rq->out[1] == *rq->in) {
- memmove(src, src + righthalf, rq->pageofs_out);
- } else if (nrpages_out == 2) {
- if (dst)
- kunmap_atomic(dst);
- DBG_BUGON(!rq->out[1]);
- dst = kmap_atomic(rq->out[1]);
- memcpy(dst, src + righthalf, rq->pageofs_out);
- }
- if (dst)
- kunmap_atomic(dst);
- kunmap_atomic(src);
- return 0;
-}
-
-int z_erofs_decompress(struct z_erofs_decompress_req *rq,
- struct list_head *pagepool)
-{
- if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED)
- return shifted_decompress(rq, pagepool);
- return decompress_generic(rq, pagepool);
-}
-
diff --git a/drivers/staging/erofs/dir.c b/drivers/staging/erofs/dir.c
deleted file mode 100644
index dbf6a151886c..000000000000
--- a/drivers/staging/erofs/dir.c
+++ /dev/null
@@ -1,151 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/dir.c
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#include "internal.h"
-
-static const unsigned char erofs_filetype_table[EROFS_FT_MAX] = {
- [EROFS_FT_UNKNOWN] = DT_UNKNOWN,
- [EROFS_FT_REG_FILE] = DT_REG,
- [EROFS_FT_DIR] = DT_DIR,
- [EROFS_FT_CHRDEV] = DT_CHR,
- [EROFS_FT_BLKDEV] = DT_BLK,
- [EROFS_FT_FIFO] = DT_FIFO,
- [EROFS_FT_SOCK] = DT_SOCK,
- [EROFS_FT_SYMLINK] = DT_LNK,
-};
-
-static void debug_one_dentry(unsigned char d_type, const char *de_name,
- unsigned int de_namelen)
-{
-#ifdef CONFIG_EROFS_FS_DEBUG
- /* since the on-disk name could not have the trailing '\0' */
- unsigned char dbg_namebuf[EROFS_NAME_LEN + 1];
-
- memcpy(dbg_namebuf, de_name, de_namelen);
- dbg_namebuf[de_namelen] = '\0';
-
- debugln("found dirent %s de_len %u d_type %d", dbg_namebuf,
- de_namelen, d_type);
-#endif
-}
-
-static int erofs_fill_dentries(struct dir_context *ctx,
- void *dentry_blk, unsigned int *ofs,
- unsigned int nameoff, unsigned int maxsize)
-{
- struct erofs_dirent *de = dentry_blk + *ofs;
- const struct erofs_dirent *end = dentry_blk + nameoff;
-
- while (de < end) {
- const char *de_name;
- unsigned int de_namelen;
- unsigned char d_type;
-
- if (de->file_type < EROFS_FT_MAX)
- d_type = erofs_filetype_table[de->file_type];
- else
- d_type = DT_UNKNOWN;
-
- nameoff = le16_to_cpu(de->nameoff);
- de_name = (char *)dentry_blk + nameoff;
-
- /* the last dirent in the block? */
- if (de + 1 >= end)
- de_namelen = strnlen(de_name, maxsize - nameoff);
- else
- de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
-
- /* a corrupted entry is found */
- if (unlikely(nameoff + de_namelen > maxsize ||
- de_namelen > EROFS_NAME_LEN)) {
- DBG_BUGON(1);
- return -EIO;
- }
-
- debug_one_dentry(d_type, de_name, de_namelen);
- if (!dir_emit(ctx, de_name, de_namelen,
- le64_to_cpu(de->nid), d_type))
- /* stopped by some reason */
- return 1;
- ++de;
- *ofs += sizeof(struct erofs_dirent);
- }
- *ofs = maxsize;
- return 0;
-}
-
-static int erofs_readdir(struct file *f, struct dir_context *ctx)
-{
- struct inode *dir = file_inode(f);
- struct address_space *mapping = dir->i_mapping;
- const size_t dirsize = i_size_read(dir);
- unsigned int i = ctx->pos / EROFS_BLKSIZ;
- unsigned int ofs = ctx->pos % EROFS_BLKSIZ;
- int err = 0;
- bool initial = true;
-
- while (ctx->pos < dirsize) {
- struct page *dentry_page;
- struct erofs_dirent *de;
- unsigned int nameoff, maxsize;
-
- dentry_page = read_mapping_page(mapping, i, NULL);
- if (IS_ERR(dentry_page))
- continue;
-
- de = (struct erofs_dirent *)kmap(dentry_page);
-
- nameoff = le16_to_cpu(de->nameoff);
-
- if (unlikely(nameoff < sizeof(struct erofs_dirent) ||
- nameoff >= PAGE_SIZE)) {
- errln("%s, invalid de[0].nameoff %u",
- __func__, nameoff);
-
- err = -EIO;
- goto skip_this;
- }
-
- maxsize = min_t(unsigned int,
- dirsize - ctx->pos + ofs, PAGE_SIZE);
-
- /* search dirents at the arbitrary position */
- if (unlikely(initial)) {
- initial = false;
-
- ofs = roundup(ofs, sizeof(struct erofs_dirent));
- if (unlikely(ofs >= nameoff))
- goto skip_this;
- }
-
- err = erofs_fill_dentries(ctx, de, &ofs, nameoff, maxsize);
-skip_this:
- kunmap(dentry_page);
-
- put_page(dentry_page);
-
- ctx->pos = blknr_to_addr(i) + ofs;
-
- if (unlikely(err))
- break;
- ++i;
- ofs = 0;
- }
- return err < 0 ? err : 0;
-}
-
-const struct file_operations erofs_dir_fops = {
- .llseek = generic_file_llseek,
- .read = generic_read_dir,
- .iterate_shared = erofs_readdir,
-};
-
diff --git a/drivers/staging/erofs/erofs_fs.h b/drivers/staging/erofs/erofs_fs.h
deleted file mode 100644
index 9f61abb7c1ca..000000000000
--- a/drivers/staging/erofs/erofs_fs.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
- *
- * linux/drivers/staging/erofs/erofs_fs.h
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is dual-licensed; you may select either the GNU General Public
- * License version 2 or Apache License, Version 2.0. See the file COPYING
- * in the main directory of the Linux distribution for more details.
- */
-#ifndef __EROFS_FS_H
-#define __EROFS_FS_H
-
-/* Enhanced(Extended) ROM File System */
-#define EROFS_SUPER_MAGIC_V1 0xE0F5E1E2
-#define EROFS_SUPER_OFFSET 1024
-
-/*
- * Any bits that aren't in EROFS_ALL_REQUIREMENTS should be
- * incompatible with this kernel version.
- */
-#define EROFS_REQUIREMENT_LZ4_0PADDING 0x00000001
-#define EROFS_ALL_REQUIREMENTS EROFS_REQUIREMENT_LZ4_0PADDING
-
-struct erofs_super_block {
-/* 0 */__le32 magic; /* in the little endian */
-/* 4 */__le32 checksum; /* crc32c(super_block) */
-/* 8 */__le32 features; /* (aka. feature_compat) */
-/* 12 */__u8 blkszbits; /* support block_size == PAGE_SIZE only */
-/* 13 */__u8 reserved;
-
-/* 14 */__le16 root_nid;
-/* 16 */__le64 inos; /* total valid ino # (== f_files - f_favail) */
-
-/* 24 */__le64 build_time; /* inode v1 time derivation */
-/* 32 */__le32 build_time_nsec;
-/* 36 */__le32 blocks; /* used for statfs */
-/* 40 */__le32 meta_blkaddr;
-/* 44 */__le32 xattr_blkaddr;
-/* 48 */__u8 uuid[16]; /* 128-bit uuid for volume */
-/* 64 */__u8 volume_name[16]; /* volume name */
-/* 80 */__le32 requirements; /* (aka. feature_incompat) */
-
-/* 84 */__u8 reserved2[44];
-} __packed; /* 128 bytes */
-
-/*
- * erofs inode data mapping:
- * 0 - inode plain without inline data A:
- * inode, [xattrs], ... | ... | no-holed data
- * 1 - inode VLE compression B (legacy):
- * inode, [xattrs], extents ... | ...
- * 2 - inode plain with inline data C:
- * inode, [xattrs], last_inline_data, ... | ... | no-holed data
- * 3 - inode compression D:
- * inode, [xattrs], map_header, extents ... | ...
- * 4~7 - reserved
- */
-enum {
- EROFS_INODE_FLAT_PLAIN,
- EROFS_INODE_FLAT_COMPRESSION_LEGACY,
- EROFS_INODE_FLAT_INLINE,
- EROFS_INODE_FLAT_COMPRESSION,
- EROFS_INODE_LAYOUT_MAX
-};
-
-static bool erofs_inode_is_data_compressed(unsigned int datamode)
-{
- if (datamode == EROFS_INODE_FLAT_COMPRESSION)
- return true;
- return datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY;
-}
-
-/* bit definitions of inode i_advise */
-#define EROFS_I_VERSION_BITS 1
-#define EROFS_I_DATA_MAPPING_BITS 3
-
-#define EROFS_I_VERSION_BIT 0
-#define EROFS_I_DATA_MAPPING_BIT 1
-
-struct erofs_inode_v1 {
-/* 0 */__le16 i_advise;
-
-/* 1 header + n-1 * 4 bytes inline xattr to keep continuity */
-/* 2 */__le16 i_xattr_icount;
-/* 4 */__le16 i_mode;
-/* 6 */__le16 i_nlink;
-/* 8 */__le32 i_size;
-/* 12 */__le32 i_reserved;
-/* 16 */union {
- /* file total compressed blocks for data mapping 1 */
- __le32 compressed_blocks;
- __le32 raw_blkaddr;
-
- /* for device files, used to indicate old/new device # */
- __le32 rdev;
- } i_u __packed;
-/* 20 */__le32 i_ino; /* only used for 32-bit stat compatibility */
-/* 24 */__le16 i_uid;
-/* 26 */__le16 i_gid;
-/* 28 */__le32 i_checksum;
-} __packed;
-
-/* 32 bytes on-disk inode */
-#define EROFS_INODE_LAYOUT_V1 0
-/* 64 bytes on-disk inode */
-#define EROFS_INODE_LAYOUT_V2 1
-
-struct erofs_inode_v2 {
- __le16 i_advise;
-
- /* 1 header + n-1 * 4 bytes inline xattr to keep continuity */
- __le16 i_xattr_icount;
- __le16 i_mode;
- __le16 i_reserved; /* 8 bytes */
- __le64 i_size; /* 16 bytes */
- union {
- /* file total compressed blocks for data mapping 1 */
- __le32 compressed_blocks;
- __le32 raw_blkaddr;
-
- /* for device files, used to indicate old/new device # */
- __le32 rdev;
- } i_u __packed;
-
- /* only used for 32-bit stat compatibility */
- __le32 i_ino; /* 24 bytes */
-
- __le32 i_uid;
- __le32 i_gid;
- __le64 i_ctime; /* 32 bytes */
- __le32 i_ctime_nsec;
- __le32 i_nlink;
- __u8 i_reserved2[12];
- __le32 i_checksum; /* 64 bytes */
-} __packed;
-
-#define EROFS_MAX_SHARED_XATTRS (128)
-/* h_shared_count between 129 ... 255 are special # */
-#define EROFS_SHARED_XATTR_EXTENT (255)
-
-/*
- * inline xattrs (n == i_xattr_icount):
- * erofs_xattr_ibody_header(1) + (n - 1) * 4 bytes
- * 12 bytes / \
- * / \
- * /-----------------------\
- * | erofs_xattr_entries+ |
- * +-----------------------+
- * inline xattrs must starts in erofs_xattr_ibody_header,
- * for read-only fs, no need to introduce h_refcount
- */
-struct erofs_xattr_ibody_header {
- __le32 h_checksum;
- __u8 h_shared_count;
- __u8 h_reserved[7];
- __le32 h_shared_xattrs[0]; /* shared xattr id array */
-} __packed;
-
-/* Name indexes */
-#define EROFS_XATTR_INDEX_USER 1
-#define EROFS_XATTR_INDEX_POSIX_ACL_ACCESS 2
-#define EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT 3
-#define EROFS_XATTR_INDEX_TRUSTED 4
-#define EROFS_XATTR_INDEX_LUSTRE 5
-#define EROFS_XATTR_INDEX_SECURITY 6
-
-/* xattr entry (for both inline & shared xattrs) */
-struct erofs_xattr_entry {
- __u8 e_name_len; /* length of name */
- __u8 e_name_index; /* attribute name index */
- __le16 e_value_size; /* size of attribute value */
- /* followed by e_name and e_value */
- char e_name[0]; /* attribute name */
-} __packed;
-
-#define ondisk_xattr_ibody_size(count) ({\
- u32 __count = le16_to_cpu(count); \
- ((__count) == 0) ? 0 : \
- sizeof(struct erofs_xattr_ibody_header) + \
- sizeof(__u32) * ((__count) - 1); })
-
-#define EROFS_XATTR_ALIGN(size) round_up(size, sizeof(struct erofs_xattr_entry))
-#define EROFS_XATTR_ENTRY_SIZE(entry) EROFS_XATTR_ALIGN( \
- sizeof(struct erofs_xattr_entry) + \
- (entry)->e_name_len + le16_to_cpu((entry)->e_value_size))
-
-/* available compression algorithm types */
-enum {
- Z_EROFS_COMPRESSION_LZ4,
- Z_EROFS_COMPRESSION_MAX
-};
-
-/*
- * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on)
- * e.g. for 4k logical cluster size, 4B if compacted 2B is off;
- * (4B) + 2B + (4B) if compacted 2B is on.
- */
-#define Z_EROFS_ADVISE_COMPACTED_2B_BIT 0
-
-#define Z_EROFS_ADVISE_COMPACTED_2B (1 << Z_EROFS_ADVISE_COMPACTED_2B_BIT)
-
-struct z_erofs_map_header {
- __le32 h_reserved1;
- __le16 h_advise;
- /*
- * bit 0-3 : algorithm type of head 1 (logical cluster type 01);
- * bit 4-7 : algorithm type of head 2 (logical cluster type 11).
- */
- __u8 h_algorithmtype;
- /*
- * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096;
- * bit 3-4 : (physical - logical) cluster bits of head 1:
- * For example, if logical clustersize = 4096, 1 for 8192.
- * bit 5-7 : (physical - logical) cluster bits of head 2.
- */
- __u8 h_clusterbits;
-};
-
-#define Z_EROFS_VLE_LEGACY_HEADER_PADDING 8
-
-/*
- * Z_EROFS Variable-sized Logical Extent cluster type:
- * 0 - literal (uncompressed) cluster
- * 1 - compressed cluster (for the head logical cluster)
- * 2 - compressed cluster (for the other logical clusters)
- *
- * In detail,
- * 0 - literal (uncompressed) cluster,
- * di_advise = 0
- * di_clusterofs = the literal data offset of the cluster
- * di_blkaddr = the blkaddr of the literal cluster
- *
- * 1 - compressed cluster (for the head logical cluster)
- * di_advise = 1
- * di_clusterofs = the decompressed data offset of the cluster
- * di_blkaddr = the blkaddr of the compressed cluster
- *
- * 2 - compressed cluster (for the other logical clusters)
- * di_advise = 2
- * di_clusterofs =
- * the decompressed data offset in its own head cluster
- * di_u.delta[0] = distance to its corresponding head cluster
- * di_u.delta[1] = distance to its corresponding tail cluster
- * (di_advise could be 0, 1 or 2)
- */
-enum {
- Z_EROFS_VLE_CLUSTER_TYPE_PLAIN,
- Z_EROFS_VLE_CLUSTER_TYPE_HEAD,
- Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD,
- Z_EROFS_VLE_CLUSTER_TYPE_RESERVED,
- Z_EROFS_VLE_CLUSTER_TYPE_MAX
-};
-
-#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS 2
-#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT 0
-
-struct z_erofs_vle_decompressed_index {
- __le16 di_advise;
- /* where to decompress in the head cluster */
- __le16 di_clusterofs;
-
- union {
- /* for the head cluster */
- __le32 blkaddr;
- /*
- * for the rest clusters
- * eg. for 4k page-sized cluster, maximum 4K*64k = 256M)
- * [0] - pointing to the head cluster
- * [1] - pointing to the tail cluster
- */
- __le16 delta[2];
- } di_u __packed; /* 8 bytes */
-} __packed;
-
-#define Z_EROFS_VLE_LEGACY_INDEX_ALIGN(size) \
- (round_up(size, sizeof(struct z_erofs_vle_decompressed_index)) + \
- sizeof(struct z_erofs_map_header) + Z_EROFS_VLE_LEGACY_HEADER_PADDING)
-
-/* dirent sorts in alphabet order, thus we can do binary search */
-struct erofs_dirent {
- __le64 nid; /* 0, node number */
- __le16 nameoff; /* 8, start offset of file name */
- __u8 file_type; /* 10, file type */
- __u8 reserved; /* 11, reserved */
-} __packed;
-
-/* file types used in inode_info->flags */
-enum {
- EROFS_FT_UNKNOWN,
- EROFS_FT_REG_FILE,
- EROFS_FT_DIR,
- EROFS_FT_CHRDEV,
- EROFS_FT_BLKDEV,
- EROFS_FT_FIFO,
- EROFS_FT_SOCK,
- EROFS_FT_SYMLINK,
- EROFS_FT_MAX
-};
-
-#define EROFS_NAME_LEN 255
-
-/* check the EROFS on-disk layout strictly at compile time */
-static inline void erofs_check_ondisk_layout_definitions(void)
-{
- BUILD_BUG_ON(sizeof(struct erofs_super_block) != 128);
- BUILD_BUG_ON(sizeof(struct erofs_inode_v1) != 32);
- BUILD_BUG_ON(sizeof(struct erofs_inode_v2) != 64);
- BUILD_BUG_ON(sizeof(struct erofs_xattr_ibody_header) != 12);
- BUILD_BUG_ON(sizeof(struct erofs_xattr_entry) != 4);
- BUILD_BUG_ON(sizeof(struct z_erofs_map_header) != 8);
- BUILD_BUG_ON(sizeof(struct z_erofs_vle_decompressed_index) != 8);
- BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
-
- BUILD_BUG_ON(BIT(Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) <
- Z_EROFS_VLE_CLUSTER_TYPE_MAX - 1);
-}
-
-#endif
-
diff --git a/drivers/staging/erofs/include/linux/tagptr.h b/drivers/staging/erofs/include/linux/tagptr.h
deleted file mode 100644
index ccd106dbd48e..000000000000
--- a/drivers/staging/erofs/include/linux/tagptr.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Tagged pointer implementation
- *
- * Copyright (C) 2018 Gao Xiang <gaoxiang25@huawei.com>
- */
-#ifndef _LINUX_TAGPTR_H
-#define _LINUX_TAGPTR_H
-
-#include <linux/types.h>
-#include <linux/build_bug.h>
-
-/*
- * the name of tagged pointer types are tagptr{1, 2, 3...}_t
- * avoid directly using the internal structs __tagptr{1, 2, 3...}
- */
-#define __MAKE_TAGPTR(n) \
-typedef struct __tagptr##n { \
- uintptr_t v; \
-} tagptr##n##_t;
-
-__MAKE_TAGPTR(1)
-__MAKE_TAGPTR(2)
-__MAKE_TAGPTR(3)
-__MAKE_TAGPTR(4)
-
-#undef __MAKE_TAGPTR
-
-extern void __compiletime_error("bad tagptr tags")
- __bad_tagptr_tags(void);
-
-extern void __compiletime_error("bad tagptr type")
- __bad_tagptr_type(void);
-
-/* fix the broken usage of "#define tagptr2_t tagptr3_t" by users */
-#define __tagptr_mask_1(ptr, n) \
- __builtin_types_compatible_p(typeof(ptr), struct __tagptr##n) ? \
- (1UL << (n)) - 1 :
-
-#define __tagptr_mask(ptr) (\
- __tagptr_mask_1(ptr, 1) ( \
- __tagptr_mask_1(ptr, 2) ( \
- __tagptr_mask_1(ptr, 3) ( \
- __tagptr_mask_1(ptr, 4) ( \
- __bad_tagptr_type(), 0)))))
-
-/* generate a tagged pointer from a raw value */
-#define tagptr_init(type, val) \
- ((typeof(type)){ .v = (uintptr_t)(val) })
-
-/*
- * directly cast a tagged pointer to the native pointer type, which
- * could be used for backward compatibility of existing code.
- */
-#define tagptr_cast_ptr(tptr) ((void *)(tptr).v)
-
-/* encode tagged pointers */
-#define tagptr_fold(type, ptr, _tags) ({ \
- const typeof(_tags) tags = (_tags); \
- if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(type))) \
- __bad_tagptr_tags(); \
-tagptr_init(type, (uintptr_t)(ptr) | tags); })
-
-/* decode tagged pointers */
-#define tagptr_unfold_ptr(tptr) \
- ((void *)((tptr).v & ~__tagptr_mask(tptr)))
-
-#define tagptr_unfold_tags(tptr) \
- ((tptr).v & __tagptr_mask(tptr))
-
-/* operations for the tagger pointer */
-#define tagptr_eq(_tptr1, _tptr2) ({ \
- typeof(_tptr1) tptr1 = (_tptr1); \
- typeof(_tptr2) tptr2 = (_tptr2); \
- (void)(&tptr1 == &tptr2); \
-(tptr1).v == (tptr2).v; })
-
-/* lock-free CAS operation */
-#define tagptr_cmpxchg(_ptptr, _o, _n) ({ \
- typeof(_ptptr) ptptr = (_ptptr); \
- typeof(_o) o = (_o); \
- typeof(_n) n = (_n); \
- (void)(&o == &n); \
- (void)(&o == ptptr); \
-tagptr_init(o, cmpxchg(&ptptr->v, o.v, n.v)); })
-
-/* wrap WRITE_ONCE if atomic update is needed */
-#define tagptr_replace_tags(_ptptr, tags) ({ \
- typeof(_ptptr) ptptr = (_ptptr); \
- *ptptr = tagptr_fold(*ptptr, tagptr_unfold_ptr(*ptptr), tags); \
-*ptptr; })
-
-#define tagptr_set_tags(_ptptr, _tags) ({ \
- typeof(_ptptr) ptptr = (_ptptr); \
- const typeof(_tags) tags = (_tags); \
- if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
- __bad_tagptr_tags(); \
- ptptr->v |= tags; \
-*ptptr; })
-
-#define tagptr_clear_tags(_ptptr, _tags) ({ \
- typeof(_ptptr) ptptr = (_ptptr); \
- const typeof(_tags) tags = (_tags); \
- if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
- __bad_tagptr_tags(); \
- ptptr->v &= ~tags; \
-*ptptr; })
-
-#endif
-
diff --git a/drivers/staging/erofs/include/trace/events/erofs.h b/drivers/staging/erofs/include/trace/events/erofs.h
deleted file mode 100644
index 660c92fc1803..000000000000
--- a/drivers/staging/erofs/include/trace/events/erofs.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM erofs
-
-#if !defined(_TRACE_EROFS_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_EROFS_H
-
-#include <linux/tracepoint.h>
-
-#define show_dev(dev) MAJOR(dev), MINOR(dev)
-#define show_dev_nid(entry) show_dev(entry->dev), entry->nid
-
-#define show_file_type(type) \
- __print_symbolic(type, \
- { 0, "FILE" }, \
- { 1, "DIR" })
-
-#define show_map_flags(flags) __print_flags(flags, "|", \
- { EROFS_GET_BLOCKS_RAW, "RAW" })
-
-#define show_mflags(flags) __print_flags(flags, "", \
- { EROFS_MAP_MAPPED, "M" }, \
- { EROFS_MAP_META, "I" }, \
- { EROFS_MAP_ZIPPED, "Z" })
-
-TRACE_EVENT(erofs_lookup,
-
- TP_PROTO(struct inode *dir, struct dentry *dentry, unsigned int flags),
-
- TP_ARGS(dir, dentry, flags),
-
- TP_STRUCT__entry(
- __field(dev_t, dev )
- __field(erofs_nid_t, nid )
- __field(const char *, name )
- __field(unsigned int, flags )
- ),
-
- TP_fast_assign(
- __entry->dev = dir->i_sb->s_dev;
- __entry->nid = EROFS_V(dir)->nid;
- __entry->name = dentry->d_name.name;
- __entry->flags = flags;
- ),
-
- TP_printk("dev = (%d,%d), pnid = %llu, name:%s, flags:%x",
- show_dev_nid(__entry),
- __entry->name,
- __entry->flags)
-);
-
-TRACE_EVENT(erofs_fill_inode,
- TP_PROTO(struct inode *inode, int isdir),
- TP_ARGS(inode, isdir),
-
- TP_STRUCT__entry(
- __field(dev_t, dev )
- __field(erofs_nid_t, nid )
- __field(erofs_blk_t, blkaddr )
- __field(unsigned int, ofs )
- __field(int, isdir )
- ),
-
- TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
- __entry->nid = EROFS_V(inode)->nid;
- __entry->blkaddr = erofs_blknr(iloc(EROFS_I_SB(inode), __entry->nid));
- __entry->ofs = erofs_blkoff(iloc(EROFS_I_SB(inode), __entry->nid));
- __entry->isdir = isdir;
- ),
-
- TP_printk("dev = (%d,%d), nid = %llu, blkaddr %u ofs %u, isdir %d",
- show_dev_nid(__entry),
- __entry->blkaddr, __entry->ofs,
- __entry->isdir)
-);
-
-TRACE_EVENT(erofs_readpage,
-
- TP_PROTO(struct page *page, bool raw),
-
- TP_ARGS(page, raw),
-
- TP_STRUCT__entry(
- __field(dev_t, dev )
- __field(erofs_nid_t, nid )
- __field(int, dir )
- __field(pgoff_t, index )
- __field(int, uptodate)
- __field(bool, raw )
- ),
-
- TP_fast_assign(
- __entry->dev = page->mapping->host->i_sb->s_dev;
- __entry->nid = EROFS_V(page->mapping->host)->nid;
- __entry->dir = S_ISDIR(page->mapping->host->i_mode);
- __entry->index = page->index;
- __entry->uptodate = PageUptodate(page);
- __entry->raw = raw;
- ),
-
- TP_printk("dev = (%d,%d), nid = %llu, %s, index = %lu, uptodate = %d "
- "raw = %d",
- show_dev_nid(__entry),
- show_file_type(__entry->dir),
- (unsigned long)__entry->index,
- __entry->uptodate,
- __entry->raw)
-);
-
-TRACE_EVENT(erofs_readpages,
-
- TP_PROTO(struct inode *inode, struct page *page, unsigned int nrpage,
- bool raw),
-
- TP_ARGS(inode, page, nrpage, raw),
-
- TP_STRUCT__entry(
- __field(dev_t, dev )
- __field(erofs_nid_t, nid )
- __field(pgoff_t, start )
- __field(unsigned int, nrpage )
- __field(bool, raw )
- ),
-
- TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
- __entry->nid = EROFS_V(inode)->nid;
- __entry->start = page->index;
- __entry->nrpage = nrpage;
- __entry->raw = raw;
- ),
-
- TP_printk("dev = (%d,%d), nid = %llu, start = %lu nrpage = %u raw = %d",
- show_dev_nid(__entry),
- (unsigned long)__entry->start,
- __entry->nrpage,
- __entry->raw)
-);
-
-DECLARE_EVENT_CLASS(erofs__map_blocks_enter,
- TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
- unsigned int flags),
-
- TP_ARGS(inode, map, flags),
-
- TP_STRUCT__entry(
- __field( dev_t, dev )
- __field( erofs_nid_t, nid )
- __field( erofs_off_t, la )
- __field( u64, llen )
- __field( unsigned int, flags )
- ),
-
- TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
- __entry->nid = EROFS_V(inode)->nid;
- __entry->la = map->m_la;
- __entry->llen = map->m_llen;
- __entry->flags = flags;
- ),
-
- TP_printk("dev = (%d,%d), nid = %llu, la %llu llen %llu flags %s",
- show_dev_nid(__entry),
- __entry->la, __entry->llen,
- __entry->flags ? show_map_flags(__entry->flags) : "NULL")
-);
-
-DEFINE_EVENT(erofs__map_blocks_enter, erofs_map_blocks_flatmode_enter,
- TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
- unsigned flags),
-
- TP_ARGS(inode, map, flags)
-);
-
-DEFINE_EVENT(erofs__map_blocks_enter, z_erofs_map_blocks_iter_enter,
- TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
- unsigned int flags),
-
- TP_ARGS(inode, map, flags)
-);
-
-DECLARE_EVENT_CLASS(erofs__map_blocks_exit,
- TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
- unsigned int flags, int ret),
-
- TP_ARGS(inode, map, flags, ret),
-
- TP_STRUCT__entry(
- __field( dev_t, dev )
- __field( erofs_nid_t, nid )
- __field( unsigned int, flags )
- __field( erofs_off_t, la )
- __field( erofs_off_t, pa )
- __field( u64, llen )
- __field( u64, plen )
- __field( unsigned int, mflags )
- __field( int, ret )
- ),
-
- TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
- __entry->nid = EROFS_V(inode)->nid;
- __entry->flags = flags;
- __entry->la = map->m_la;
- __entry->pa = map->m_pa;
- __entry->llen = map->m_llen;
- __entry->plen = map->m_plen;
- __entry->mflags = map->m_flags;
- __entry->ret = ret;
- ),
-
- TP_printk("dev = (%d,%d), nid = %llu, flags %s "
- "la %llu pa %llu llen %llu plen %llu mflags %s ret %d",
- show_dev_nid(__entry),
- __entry->flags ? show_map_flags(__entry->flags) : "NULL",
- __entry->la, __entry->pa, __entry->llen, __entry->plen,
- show_mflags(__entry->mflags), __entry->ret)
-);
-
-DEFINE_EVENT(erofs__map_blocks_exit, erofs_map_blocks_flatmode_exit,
- TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
- unsigned flags, int ret),
-
- TP_ARGS(inode, map, flags, ret)
-);
-
-DEFINE_EVENT(erofs__map_blocks_exit, z_erofs_map_blocks_iter_exit,
- TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
- unsigned int flags, int ret),
-
- TP_ARGS(inode, map, flags, ret)
-);
-
-TRACE_EVENT(erofs_destroy_inode,
- TP_PROTO(struct inode *inode),
-
- TP_ARGS(inode),
-
- TP_STRUCT__entry(
- __field( dev_t, dev )
- __field( erofs_nid_t, nid )
- ),
-
- TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
- __entry->nid = EROFS_V(inode)->nid;
- ),
-
- TP_printk("dev = (%d,%d), nid = %llu", show_dev_nid(__entry))
-);
-
-#endif /* _TRACE_EROFS_H */
-
- /* This part must be outside protection */
-#include <trace/define_trace.h>
diff --git a/drivers/staging/erofs/inode.c b/drivers/staging/erofs/inode.c
deleted file mode 100644
index 4c3d8bf8d249..000000000000
--- a/drivers/staging/erofs/inode.c
+++ /dev/null
@@ -1,332 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/inode.c
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#include "xattr.h"
-
-#include <trace/events/erofs.h>
-
-/* no locking */
-static int read_inode(struct inode *inode, void *data)
-{
- struct erofs_vnode *vi = EROFS_V(inode);
- struct erofs_inode_v1 *v1 = data;
- const unsigned int advise = le16_to_cpu(v1->i_advise);
- erofs_blk_t nblks = 0;
-
- vi->datamode = __inode_data_mapping(advise);
-
- if (unlikely(vi->datamode >= EROFS_INODE_LAYOUT_MAX)) {
- errln("unsupported data mapping %u of nid %llu",
- vi->datamode, vi->nid);
- DBG_BUGON(1);
- return -EIO;
- }
-
- if (__inode_version(advise) == EROFS_INODE_LAYOUT_V2) {
- struct erofs_inode_v2 *v2 = data;
-
- vi->inode_isize = sizeof(struct erofs_inode_v2);
- vi->xattr_isize = ondisk_xattr_ibody_size(v2->i_xattr_icount);
-
- inode->i_mode = le16_to_cpu(v2->i_mode);
- if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)) {
- vi->raw_blkaddr = le32_to_cpu(v2->i_u.raw_blkaddr);
- } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
- inode->i_rdev =
- new_decode_dev(le32_to_cpu(v2->i_u.rdev));
- } else if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
- inode->i_rdev = 0;
- } else {
- return -EIO;
- }
-
- i_uid_write(inode, le32_to_cpu(v2->i_uid));
- i_gid_write(inode, le32_to_cpu(v2->i_gid));
- set_nlink(inode, le32_to_cpu(v2->i_nlink));
-
- /* ns timestamp */
- inode->i_mtime.tv_sec = inode->i_ctime.tv_sec =
- le64_to_cpu(v2->i_ctime);
- inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec =
- le32_to_cpu(v2->i_ctime_nsec);
-
- inode->i_size = le64_to_cpu(v2->i_size);
-
- /* total blocks for compressed files */
- if (is_inode_layout_compression(inode))
- nblks = le32_to_cpu(v2->i_u.compressed_blocks);
- } else if (__inode_version(advise) == EROFS_INODE_LAYOUT_V1) {
- struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
-
- vi->inode_isize = sizeof(struct erofs_inode_v1);
- vi->xattr_isize = ondisk_xattr_ibody_size(v1->i_xattr_icount);
-
- inode->i_mode = le16_to_cpu(v1->i_mode);
- if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)) {
- vi->raw_blkaddr = le32_to_cpu(v1->i_u.raw_blkaddr);
- } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
- inode->i_rdev =
- new_decode_dev(le32_to_cpu(v1->i_u.rdev));
- } else if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
- inode->i_rdev = 0;
- } else {
- return -EIO;
- }
-
- i_uid_write(inode, le16_to_cpu(v1->i_uid));
- i_gid_write(inode, le16_to_cpu(v1->i_gid));
- set_nlink(inode, le16_to_cpu(v1->i_nlink));
-
- /* use build time to derive all file time */
- inode->i_mtime.tv_sec = inode->i_ctime.tv_sec =
- sbi->build_time;
- inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec =
- sbi->build_time_nsec;
-
- inode->i_size = le32_to_cpu(v1->i_size);
- if (is_inode_layout_compression(inode))
- nblks = le32_to_cpu(v1->i_u.compressed_blocks);
- } else {
- errln("unsupported on-disk inode version %u of nid %llu",
- __inode_version(advise), vi->nid);
- DBG_BUGON(1);
- return -EIO;
- }
-
- if (!nblks)
- /* measure inode.i_blocks as generic filesystems */
- inode->i_blocks = roundup(inode->i_size, EROFS_BLKSIZ) >> 9;
- else
- inode->i_blocks = nblks << LOG_SECTORS_PER_BLOCK;
- return 0;
-}
-
-/*
- * try_lock can be required since locking order is:
- * file data(fs_inode)
- * meta(bd_inode)
- * but the majority of the callers is "iget",
- * in that case we are pretty sure no deadlock since
- * no data operations exist. However I tend to
- * try_lock since it takes no much overhead and
- * will success immediately.
- */
-static int fill_inline_data(struct inode *inode, void *data,
- unsigned int m_pofs)
-{
- struct erofs_vnode *vi = EROFS_V(inode);
- struct erofs_sb_info *sbi = EROFS_I_SB(inode);
-
- /* should be inode inline C */
- if (!is_inode_flat_inline(inode))
- return 0;
-
- /* fast symlink (following ext4) */
- if (S_ISLNK(inode->i_mode) && inode->i_size < PAGE_SIZE) {
- char *lnk = erofs_kmalloc(sbi, inode->i_size + 1, GFP_KERNEL);
-
- if (unlikely(!lnk))
- return -ENOMEM;
-
- m_pofs += vi->inode_isize + vi->xattr_isize;
-
- /* inline symlink data shouldn't across page boundary as well */
- if (unlikely(m_pofs + inode->i_size > PAGE_SIZE)) {
- DBG_BUGON(1);
- kfree(lnk);
- return -EIO;
- }
-
- /* get in-page inline data */
- memcpy(lnk, data + m_pofs, inode->i_size);
- lnk[inode->i_size] = '\0';
-
- inode->i_link = lnk;
- set_inode_fast_symlink(inode);
- }
- return 0;
-}
-
-static int fill_inode(struct inode *inode, int isdir)
-{
- struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
- struct erofs_vnode *vi = EROFS_V(inode);
- struct page *page;
- void *data;
- int err;
- erofs_blk_t blkaddr;
- unsigned int ofs;
-
- trace_erofs_fill_inode(inode, isdir);
-
- blkaddr = erofs_blknr(iloc(sbi, vi->nid));
- ofs = erofs_blkoff(iloc(sbi, vi->nid));
-
- debugln("%s, reading inode nid %llu at %u of blkaddr %u",
- __func__, vi->nid, ofs, blkaddr);
-
- page = erofs_get_meta_page(inode->i_sb, blkaddr, isdir);
-
- if (IS_ERR(page)) {
- errln("failed to get inode (nid: %llu) page, err %ld",
- vi->nid, PTR_ERR(page));
- return PTR_ERR(page);
- }
-
- DBG_BUGON(!PageUptodate(page));
- data = page_address(page);
-
- err = read_inode(inode, data + ofs);
- if (!err) {
- /* setup the new inode */
- if (S_ISREG(inode->i_mode)) {
- inode->i_op = &erofs_generic_iops;
- inode->i_fop = &generic_ro_fops;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &erofs_dir_iops;
- inode->i_fop = &erofs_dir_fops;
- } else if (S_ISLNK(inode->i_mode)) {
- /* by default, page_get_link is used for symlink */
- inode->i_op = &erofs_symlink_iops;
- inode_nohighmem(inode);
- } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
- S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
- inode->i_op = &erofs_generic_iops;
- init_special_inode(inode, inode->i_mode, inode->i_rdev);
- goto out_unlock;
- } else {
- err = -EIO;
- goto out_unlock;
- }
-
- if (is_inode_layout_compression(inode)) {
- err = z_erofs_fill_inode(inode);
- goto out_unlock;
- }
-
- inode->i_mapping->a_ops = &erofs_raw_access_aops;
-
- /* fill last page if inline data is available */
- err = fill_inline_data(inode, data, ofs);
- }
-
-out_unlock:
- unlock_page(page);
- put_page(page);
- return err;
-}
-
-/*
- * erofs nid is 64bits, but i_ino is 'unsigned long', therefore
- * we should do more for 32-bit platform to find the right inode.
- */
-#if BITS_PER_LONG == 32
-static int erofs_ilookup_test_actor(struct inode *inode, void *opaque)
-{
- const erofs_nid_t nid = *(erofs_nid_t *)opaque;
-
- return EROFS_V(inode)->nid == nid;
-}
-
-static int erofs_iget_set_actor(struct inode *inode, void *opaque)
-{
- const erofs_nid_t nid = *(erofs_nid_t *)opaque;
-
- inode->i_ino = erofs_inode_hash(nid);
- return 0;
-}
-#endif
-
-static inline struct inode *erofs_iget_locked(struct super_block *sb,
- erofs_nid_t nid)
-{
- const unsigned long hashval = erofs_inode_hash(nid);
-
-#if BITS_PER_LONG >= 64
- /* it is safe to use iget_locked for >= 64-bit platform */
- return iget_locked(sb, hashval);
-#else
- return iget5_locked(sb, hashval, erofs_ilookup_test_actor,
- erofs_iget_set_actor, &nid);
-#endif
-}
-
-struct inode *erofs_iget(struct super_block *sb,
- erofs_nid_t nid,
- bool isdir)
-{
- struct inode *inode = erofs_iget_locked(sb, nid);
-
- if (unlikely(!inode))
- return ERR_PTR(-ENOMEM);
-
- if (inode->i_state & I_NEW) {
- int err;
- struct erofs_vnode *vi = EROFS_V(inode);
-
- vi->nid = nid;
-
- err = fill_inode(inode, isdir);
- if (likely(!err))
- unlock_new_inode(inode);
- else {
- iget_failed(inode);
- inode = ERR_PTR(err);
- }
- }
- return inode;
-}
-
-int erofs_getattr(const struct path *path, struct kstat *stat,
- u32 request_mask, unsigned int query_flags)
-{
- struct inode *const inode = d_inode(path->dentry);
-
- if (is_inode_layout_compression(inode))
- stat->attributes |= STATX_ATTR_COMPRESSED;
-
- stat->attributes |= STATX_ATTR_IMMUTABLE;
- stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
- STATX_ATTR_IMMUTABLE);
-
- generic_fillattr(inode, stat);
- return 0;
-}
-
-const struct inode_operations erofs_generic_iops = {
- .getattr = erofs_getattr,
-#ifdef CONFIG_EROFS_FS_XATTR
- .listxattr = erofs_listxattr,
-#endif
- .get_acl = erofs_get_acl,
-};
-
-const struct inode_operations erofs_symlink_iops = {
- .get_link = page_get_link,
- .getattr = erofs_getattr,
-#ifdef CONFIG_EROFS_FS_XATTR
- .listxattr = erofs_listxattr,
-#endif
- .get_acl = erofs_get_acl,
-};
-
-const struct inode_operations erofs_fast_symlink_iops = {
- .get_link = simple_get_link,
- .getattr = erofs_getattr,
-#ifdef CONFIG_EROFS_FS_XATTR
- .listxattr = erofs_listxattr,
-#endif
- .get_acl = erofs_get_acl,
-};
-
diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h
deleted file mode 100644
index 963cc1b8b896..000000000000
--- a/drivers/staging/erofs/internal.h
+++ /dev/null
@@ -1,642 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * linux/drivers/staging/erofs/internal.h
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#ifndef __INTERNAL_H
-#define __INTERNAL_H
-
-#include <linux/fs.h>
-#include <linux/dcache.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/bio.h>
-#include <linux/buffer_head.h>
-#include <linux/cleancache.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include "erofs_fs.h"
-
-/* redefine pr_fmt "erofs: " */
-#undef pr_fmt
-#define pr_fmt(fmt) "erofs: " fmt
-
-#define errln(x, ...) pr_err(x "\n", ##__VA_ARGS__)
-#define infoln(x, ...) pr_info(x "\n", ##__VA_ARGS__)
-#ifdef CONFIG_EROFS_FS_DEBUG
-#define debugln(x, ...) pr_debug(x "\n", ##__VA_ARGS__)
-
-#define dbg_might_sleep might_sleep
-#define DBG_BUGON BUG_ON
-#else
-#define debugln(x, ...) ((void)0)
-
-#define dbg_might_sleep() ((void)0)
-#define DBG_BUGON(x) ((void)(x))
-#endif
-
-enum {
- FAULT_KMALLOC,
- FAULT_READ_IO,
- FAULT_MAX,
-};
-
-#ifdef CONFIG_EROFS_FAULT_INJECTION
-extern const char *erofs_fault_name[FAULT_MAX];
-#define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1 << (type)))
-
-struct erofs_fault_info {
- atomic_t inject_ops;
- unsigned int inject_rate;
- unsigned int inject_type;
-};
-#endif
-
-#ifdef CONFIG_EROFS_FS_ZIP_CACHE_BIPOLAR
-#define EROFS_FS_ZIP_CACHE_LVL (2)
-#elif defined(EROFS_FS_ZIP_CACHE_UNIPOLAR)
-#define EROFS_FS_ZIP_CACHE_LVL (1)
-#else
-#define EROFS_FS_ZIP_CACHE_LVL (0)
-#endif
-
-#if (!defined(EROFS_FS_HAS_MANAGED_CACHE) && (EROFS_FS_ZIP_CACHE_LVL > 0))
-#define EROFS_FS_HAS_MANAGED_CACHE
-#endif
-
-/* EROFS_SUPER_MAGIC_V1 to represent the whole file system */
-#define EROFS_SUPER_MAGIC EROFS_SUPER_MAGIC_V1
-
-typedef u64 erofs_nid_t;
-
-struct erofs_sb_info {
- /* list for all registered superblocks, mainly for shrinker */
- struct list_head list;
- struct mutex umount_mutex;
-
- u32 blocks;
- u32 meta_blkaddr;
-#ifdef CONFIG_EROFS_FS_XATTR
- u32 xattr_blkaddr;
-#endif
-
- /* inode slot unit size in bit shift */
- unsigned char islotbits;
-#ifdef CONFIG_EROFS_FS_ZIP
- /* cluster size in bit shift */
- unsigned char clusterbits;
-
- /* the dedicated workstation for compression */
- struct radix_tree_root workstn_tree;
-
- /* threshold for decompression synchronously */
- unsigned int max_sync_decompress_pages;
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
- struct inode *managed_cache;
-#endif
-
-#endif
-
- u32 build_time_nsec;
- u64 build_time;
-
- /* what we really care is nid, rather than ino.. */
- erofs_nid_t root_nid;
- /* used for statfs, f_files - f_favail */
- u64 inos;
-
- u8 uuid[16]; /* 128-bit uuid for volume */
- u8 volume_name[16]; /* volume name */
- u32 requirements;
-
- char *dev_name;
-
- unsigned int mount_opt;
- unsigned int shrinker_run_no;
-
-#ifdef CONFIG_EROFS_FAULT_INJECTION
- struct erofs_fault_info fault_info; /* For fault injection */
-#endif
-};
-
-#ifdef CONFIG_EROFS_FAULT_INJECTION
-#define erofs_show_injection_info(type) \
- infoln("inject %s in %s of %pS", erofs_fault_name[type], \
- __func__, __builtin_return_address(0))
-
-static inline bool time_to_inject(struct erofs_sb_info *sbi, int type)
-{
- struct erofs_fault_info *ffi = &sbi->fault_info;
-
- if (!ffi->inject_rate)
- return false;
-
- if (!IS_FAULT_SET(ffi, type))
- return false;
-
- atomic_inc(&ffi->inject_ops);
- if (atomic_read(&ffi->inject_ops) >= ffi->inject_rate) {
- atomic_set(&ffi->inject_ops, 0);
- return true;
- }
- return false;
-}
-#else
-static inline bool time_to_inject(struct erofs_sb_info *sbi, int type)
-{
- return false;
-}
-
-static inline void erofs_show_injection_info(int type)
-{
-}
-#endif
-
-static inline void *erofs_kmalloc(struct erofs_sb_info *sbi,
- size_t size, gfp_t flags)
-{
- if (time_to_inject(sbi, FAULT_KMALLOC)) {
- erofs_show_injection_info(FAULT_KMALLOC);
- return NULL;
- }
- return kmalloc(size, flags);
-}
-
-#define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info)
-#define EROFS_I_SB(inode) ((struct erofs_sb_info *)(inode)->i_sb->s_fs_info)
-
-/* Mount flags set via mount options or defaults */
-#define EROFS_MOUNT_XATTR_USER 0x00000010
-#define EROFS_MOUNT_POSIX_ACL 0x00000020
-#define EROFS_MOUNT_FAULT_INJECTION 0x00000040
-
-#define clear_opt(sbi, option) ((sbi)->mount_opt &= ~EROFS_MOUNT_##option)
-#define set_opt(sbi, option) ((sbi)->mount_opt |= EROFS_MOUNT_##option)
-#define test_opt(sbi, option) ((sbi)->mount_opt & EROFS_MOUNT_##option)
-
-#ifdef CONFIG_EROFS_FS_ZIP
-#define erofs_workstn_lock(sbi) xa_lock(&(sbi)->workstn_tree)
-#define erofs_workstn_unlock(sbi) xa_unlock(&(sbi)->workstn_tree)
-
-/* basic unit of the workstation of a super_block */
-struct erofs_workgroup {
- /* the workgroup index in the workstation */
- pgoff_t index;
-
- /* overall workgroup reference count */
- atomic_t refcount;
-};
-
-#define EROFS_LOCKED_MAGIC (INT_MIN | 0xE0F510CCL)
-
-#if defined(CONFIG_SMP)
-static inline bool erofs_workgroup_try_to_freeze(struct erofs_workgroup *grp,
- int val)
-{
- preempt_disable();
- if (val != atomic_cmpxchg(&grp->refcount, val, EROFS_LOCKED_MAGIC)) {
- preempt_enable();
- return false;
- }
- return true;
-}
-
-static inline void erofs_workgroup_unfreeze(struct erofs_workgroup *grp,
- int orig_val)
-{
- /*
- * other observers should notice all modifications
- * in the freezing period.
- */
- smp_mb();
- atomic_set(&grp->refcount, orig_val);
- preempt_enable();
-}
-
-static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp)
-{
- return atomic_cond_read_relaxed(&grp->refcount,
- VAL != EROFS_LOCKED_MAGIC);
-}
-#else
-static inline bool erofs_workgroup_try_to_freeze(struct erofs_workgroup *grp,
- int val)
-{
- preempt_disable();
- /* no need to spin on UP platforms, let's just disable preemption. */
- if (val != atomic_read(&grp->refcount)) {
- preempt_enable();
- return false;
- }
- return true;
-}
-
-static inline void erofs_workgroup_unfreeze(struct erofs_workgroup *grp,
- int orig_val)
-{
- preempt_enable();
-}
-
-static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp)
-{
- int v = atomic_read(&grp->refcount);
-
- /* workgroup is never freezed on uniprocessor systems */
- DBG_BUGON(v == EROFS_LOCKED_MAGIC);
- return v;
-}
-#endif
-
-int erofs_workgroup_put(struct erofs_workgroup *grp);
-struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
- pgoff_t index, bool *tag);
-int erofs_register_workgroup(struct super_block *sb,
- struct erofs_workgroup *grp, bool tag);
-unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
- unsigned long nr_shrink, bool cleanup);
-void erofs_workgroup_free_rcu(struct erofs_workgroup *grp);
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
-int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
- struct erofs_workgroup *egrp);
-int erofs_try_to_free_cached_page(struct address_space *mapping,
- struct page *page);
-
-#define MNGD_MAPPING(sbi) ((sbi)->managed_cache->i_mapping)
-static inline bool erofs_page_is_managed(const struct erofs_sb_info *sbi,
- struct page *page)
-{
- return page->mapping == MNGD_MAPPING(sbi);
-}
-#else
-#define MNGD_MAPPING(sbi) (NULL)
-static inline bool erofs_page_is_managed(const struct erofs_sb_info *sbi,
- struct page *page) { return false; }
-#endif
-
-#define DEFAULT_MAX_SYNC_DECOMPRESS_PAGES 3
-
-static inline bool __should_decompress_synchronously(struct erofs_sb_info *sbi,
- unsigned int nr)
-{
- return nr <= sbi->max_sync_decompress_pages;
-}
-
-int __init z_erofs_init_zip_subsystem(void);
-void z_erofs_exit_zip_subsystem(void);
-#else
-/* dummy initializer/finalizer for the decompression subsystem */
-static inline int z_erofs_init_zip_subsystem(void) { return 0; }
-static inline void z_erofs_exit_zip_subsystem(void) {}
-#endif
-
-/* we strictly follow PAGE_SIZE and no buffer head yet */
-#define LOG_BLOCK_SIZE PAGE_SHIFT
-
-#undef LOG_SECTORS_PER_BLOCK
-#define LOG_SECTORS_PER_BLOCK (PAGE_SHIFT - 9)
-
-#undef SECTORS_PER_BLOCK
-#define SECTORS_PER_BLOCK (1 << SECTORS_PER_BLOCK)
-
-#define EROFS_BLKSIZ (1 << LOG_BLOCK_SIZE)
-
-#if (EROFS_BLKSIZ % 4096 || !EROFS_BLKSIZ)
-#error erofs cannot be used in this platform
-#endif
-
-#define ROOT_NID(sb) ((sb)->root_nid)
-
-#ifdef CONFIG_EROFS_FS_ZIP
-/* hard limit of pages per compressed cluster */
-#define Z_EROFS_CLUSTER_MAX_PAGES (CONFIG_EROFS_FS_CLUSTER_PAGE_LIMIT)
-
-/* page count of a compressed cluster */
-#define erofs_clusterpages(sbi) ((1 << (sbi)->clusterbits) / PAGE_SIZE)
-
-#define EROFS_PCPUBUF_NR_PAGES Z_EROFS_CLUSTER_MAX_PAGES
-#else
-#define EROFS_PCPUBUF_NR_PAGES 0
-#endif
-
-typedef u64 erofs_off_t;
-
-/* data type for filesystem-wide blocks number */
-typedef u32 erofs_blk_t;
-
-#define erofs_blknr(addr) ((addr) / EROFS_BLKSIZ)
-#define erofs_blkoff(addr) ((addr) % EROFS_BLKSIZ)
-#define blknr_to_addr(nr) ((erofs_off_t)(nr) * EROFS_BLKSIZ)
-
-static inline erofs_off_t iloc(struct erofs_sb_info *sbi, erofs_nid_t nid)
-{
- return blknr_to_addr(sbi->meta_blkaddr) + (nid << sbi->islotbits);
-}
-
-/* atomic flag definitions */
-#define EROFS_V_EA_INITED_BIT 0
-#define EROFS_V_Z_INITED_BIT 1
-
-/* bitlock definitions (arranged in reverse order) */
-#define EROFS_V_BL_XATTR_BIT (BITS_PER_LONG - 1)
-#define EROFS_V_BL_Z_BIT (BITS_PER_LONG - 2)
-
-struct erofs_vnode {
- erofs_nid_t nid;
-
- /* atomic flags (including bitlocks) */
- unsigned long flags;
-
- unsigned char datamode;
- unsigned char inode_isize;
- unsigned short xattr_isize;
-
- unsigned xattr_shared_count;
- unsigned *xattr_shared_xattrs;
-
- union {
- erofs_blk_t raw_blkaddr;
-#ifdef CONFIG_EROFS_FS_ZIP
- struct {
- unsigned short z_advise;
- unsigned char z_algorithmtype[2];
- unsigned char z_logical_clusterbits;
- unsigned char z_physical_clusterbits[2];
- };
-#endif
- };
- /* the corresponding vfs inode */
- struct inode vfs_inode;
-};
-
-#define EROFS_V(ptr) \
- container_of(ptr, struct erofs_vnode, vfs_inode)
-
-#define __inode_advise(x, bit, bits) \
- (((x) >> (bit)) & ((1 << (bits)) - 1))
-
-#define __inode_version(advise) \
- __inode_advise(advise, EROFS_I_VERSION_BIT, \
- EROFS_I_VERSION_BITS)
-
-#define __inode_data_mapping(advise) \
- __inode_advise(advise, EROFS_I_DATA_MAPPING_BIT,\
- EROFS_I_DATA_MAPPING_BITS)
-
-static inline unsigned long inode_datablocks(struct inode *inode)
-{
- /* since i_size cannot be changed */
- return DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
-}
-
-static inline bool is_inode_layout_compression(struct inode *inode)
-{
- return erofs_inode_is_data_compressed(EROFS_V(inode)->datamode);
-}
-
-static inline bool is_inode_flat_inline(struct inode *inode)
-{
- return EROFS_V(inode)->datamode == EROFS_INODE_FLAT_INLINE;
-}
-
-extern const struct super_operations erofs_sops;
-
-extern const struct address_space_operations erofs_raw_access_aops;
-#ifdef CONFIG_EROFS_FS_ZIP
-extern const struct address_space_operations z_erofs_vle_normalaccess_aops;
-#endif
-
-/*
- * Logical to physical block mapping, used by erofs_map_blocks()
- *
- * Different with other file systems, it is used for 2 access modes:
- *
- * 1) RAW access mode:
- *
- * Users pass a valid (m_lblk, m_lofs -- usually 0) pair,
- * and get the valid m_pblk, m_pofs and the longest m_len(in bytes).
- *
- * Note that m_lblk in the RAW access mode refers to the number of
- * the compressed ondisk block rather than the uncompressed
- * in-memory block for the compressed file.
- *
- * m_pofs equals to m_lofs except for the inline data page.
- *
- * 2) Normal access mode:
- *
- * If the inode is not compressed, it has no difference with
- * the RAW access mode. However, if the inode is compressed,
- * users should pass a valid (m_lblk, m_lofs) pair, and get
- * the needed m_pblk, m_pofs, m_len to get the compressed data
- * and the updated m_lblk, m_lofs which indicates the start
- * of the corresponding uncompressed data in the file.
- */
-enum {
- BH_Zipped = BH_PrivateStart,
- BH_FullMapped,
-};
-
-/* Has a disk mapping */
-#define EROFS_MAP_MAPPED (1 << BH_Mapped)
-/* Located in metadata (could be copied from bd_inode) */
-#define EROFS_MAP_META (1 << BH_Meta)
-/* The extent has been compressed */
-#define EROFS_MAP_ZIPPED (1 << BH_Zipped)
-/* The length of extent is full */
-#define EROFS_MAP_FULL_MAPPED (1 << BH_FullMapped)
-
-struct erofs_map_blocks {
- erofs_off_t m_pa, m_la;
- u64 m_plen, m_llen;
-
- unsigned int m_flags;
-
- struct page *mpage;
-};
-
-/* Flags used by erofs_map_blocks() */
-#define EROFS_GET_BLOCKS_RAW 0x0001
-
-/* zmap.c */
-#ifdef CONFIG_EROFS_FS_ZIP
-int z_erofs_fill_inode(struct inode *inode);
-int z_erofs_map_blocks_iter(struct inode *inode,
- struct erofs_map_blocks *map,
- int flags);
-#else
-static inline int z_erofs_fill_inode(struct inode *inode) { return -ENOTSUPP; }
-static inline int z_erofs_map_blocks_iter(struct inode *inode,
- struct erofs_map_blocks *map,
- int flags)
-{
- return -ENOTSUPP;
-}
-#endif
-
-/* data.c */
-static inline struct bio *
-erofs_grab_bio(struct super_block *sb,
- erofs_blk_t blkaddr, unsigned int nr_pages, void *bi_private,
- bio_end_io_t endio, bool nofail)
-{
- const gfp_t gfp = GFP_NOIO;
- struct bio *bio;
-
- do {
- if (nr_pages == 1) {
- bio = bio_alloc(gfp | (nofail ? __GFP_NOFAIL : 0), 1);
- if (unlikely(!bio)) {
- DBG_BUGON(nofail);
- return ERR_PTR(-ENOMEM);
- }
- break;
- }
- bio = bio_alloc(gfp, nr_pages);
- nr_pages /= 2;
- } while (unlikely(!bio));
-
- bio->bi_end_io = endio;
- bio_set_dev(bio, sb->s_bdev);
- bio->bi_iter.bi_sector = (sector_t)blkaddr << LOG_SECTORS_PER_BLOCK;
- bio->bi_private = bi_private;
- return bio;
-}
-
-static inline void __submit_bio(struct bio *bio, unsigned op, unsigned op_flags)
-{
- bio_set_op_attrs(bio, op, op_flags);
- submit_bio(bio);
-}
-
-#ifndef CONFIG_EROFS_FS_IO_MAX_RETRIES
-#define EROFS_IO_MAX_RETRIES_NOFAIL 0
-#else
-#define EROFS_IO_MAX_RETRIES_NOFAIL CONFIG_EROFS_FS_IO_MAX_RETRIES
-#endif
-
-struct page *__erofs_get_meta_page(struct super_block *sb, erofs_blk_t blkaddr,
- bool prio, bool nofail);
-
-static inline struct page *erofs_get_meta_page(struct super_block *sb,
- erofs_blk_t blkaddr, bool prio)
-{
- return __erofs_get_meta_page(sb, blkaddr, prio, false);
-}
-
-static inline struct page *erofs_get_meta_page_nofail(struct super_block *sb,
- erofs_blk_t blkaddr, bool prio)
-{
- return __erofs_get_meta_page(sb, blkaddr, prio, true);
-}
-
-int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int);
-
-static inline struct page *
-erofs_get_inline_page(struct inode *inode,
- erofs_blk_t blkaddr)
-{
- return erofs_get_meta_page(inode->i_sb,
- blkaddr, S_ISDIR(inode->i_mode));
-}
-
-/* inode.c */
-static inline unsigned long erofs_inode_hash(erofs_nid_t nid)
-{
-#if BITS_PER_LONG == 32
- return (nid >> 32) ^ (nid & 0xffffffff);
-#else
- return nid;
-#endif
-}
-
-extern const struct inode_operations erofs_generic_iops;
-extern const struct inode_operations erofs_symlink_iops;
-extern const struct inode_operations erofs_fast_symlink_iops;
-
-static inline void set_inode_fast_symlink(struct inode *inode)
-{
- inode->i_op = &erofs_fast_symlink_iops;
-}
-
-static inline bool is_inode_fast_symlink(struct inode *inode)
-{
- return inode->i_op == &erofs_fast_symlink_iops;
-}
-
-struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool dir);
-int erofs_getattr(const struct path *path, struct kstat *stat,
- u32 request_mask, unsigned int query_flags);
-
-/* namei.c */
-extern const struct inode_operations erofs_dir_iops;
-
-int erofs_namei(struct inode *dir, struct qstr *name,
- erofs_nid_t *nid, unsigned int *d_type);
-
-/* dir.c */
-extern const struct file_operations erofs_dir_fops;
-
-static inline void *erofs_vmap(struct page **pages, unsigned int count)
-{
-#ifdef CONFIG_EROFS_FS_USE_VM_MAP_RAM
- int i = 0;
-
- while (1) {
- void *addr = vm_map_ram(pages, count, -1, PAGE_KERNEL);
- /* retry two more times (totally 3 times) */
- if (addr || ++i >= 3)
- return addr;
- vm_unmap_aliases();
- }
- return NULL;
-#else
- return vmap(pages, count, VM_MAP, PAGE_KERNEL);
-#endif
-}
-
-static inline void erofs_vunmap(const void *mem, unsigned int count)
-{
-#ifdef CONFIG_EROFS_FS_USE_VM_MAP_RAM
- vm_unmap_ram(mem, count);
-#else
- vunmap(mem);
-#endif
-}
-
-/* utils.c */
-extern struct shrinker erofs_shrinker_info;
-
-struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp);
-
-#if (EROFS_PCPUBUF_NR_PAGES > 0)
-void *erofs_get_pcpubuf(unsigned int pagenr);
-#define erofs_put_pcpubuf(buf) do { \
- (void)&(buf); \
- preempt_enable(); \
-} while (0)
-#else
-static inline void *erofs_get_pcpubuf(unsigned int pagenr)
-{
- return ERR_PTR(-ENOTSUPP);
-}
-
-#define erofs_put_pcpubuf(buf) do {} while (0)
-#endif
-
-void erofs_register_super(struct super_block *sb);
-void erofs_unregister_super(struct super_block *sb);
-
-#ifndef lru_to_page
-#define lru_to_page(head) (list_entry((head)->prev, struct page, lru))
-#endif
-
-#endif
-
diff --git a/drivers/staging/erofs/namei.c b/drivers/staging/erofs/namei.c
deleted file mode 100644
index fd3ae78d0ba5..000000000000
--- a/drivers/staging/erofs/namei.c
+++ /dev/null
@@ -1,256 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/namei.c
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#include "internal.h"
-#include "xattr.h"
-
-#include <trace/events/erofs.h>
-
-struct erofs_qstr {
- const unsigned char *name;
- const unsigned char *end;
-};
-
-/* based on the end of qn is accurate and it must have the trailing '\0' */
-static inline int dirnamecmp(const struct erofs_qstr *qn,
- const struct erofs_qstr *qd,
- unsigned int *matched)
-{
- unsigned int i = *matched;
-
- /*
- * on-disk error, let's only BUG_ON in the debugging mode.
- * otherwise, it will return 1 to just skip the invalid name
- * and go on (in consideration of the lookup performance).
- */
- DBG_BUGON(qd->name > qd->end);
-
- /* qd could not have trailing '\0' */
- /* However it is absolutely safe if < qd->end */
- while (qd->name + i < qd->end && qd->name[i] != '\0') {
- if (qn->name[i] != qd->name[i]) {
- *matched = i;
- return qn->name[i] > qd->name[i] ? 1 : -1;
- }
- ++i;
- }
- *matched = i;
- /* See comments in __d_alloc on the terminating NUL character */
- return qn->name[i] == '\0' ? 0 : 1;
-}
-
-#define nameoff_from_disk(off, sz) (le16_to_cpu(off) & ((sz) - 1))
-
-static struct erofs_dirent *find_target_dirent(struct erofs_qstr *name,
- u8 *data,
- unsigned int dirblksize,
- const int ndirents)
-{
- int head, back;
- unsigned int startprfx, endprfx;
- struct erofs_dirent *const de = (struct erofs_dirent *)data;
-
- /* since the 1st dirent has been evaluated previously */
- head = 1;
- back = ndirents - 1;
- startprfx = endprfx = 0;
-
- while (head <= back) {
- const int mid = head + (back - head) / 2;
- const int nameoff = nameoff_from_disk(de[mid].nameoff,
- dirblksize);
- unsigned int matched = min(startprfx, endprfx);
- struct erofs_qstr dname = {
- .name = data + nameoff,
- .end = unlikely(mid >= ndirents - 1) ?
- data + dirblksize :
- data + nameoff_from_disk(de[mid + 1].nameoff,
- dirblksize)
- };
-
- /* string comparison without already matched prefix */
- int ret = dirnamecmp(name, &dname, &matched);
-
- if (unlikely(!ret)) {
- return de + mid;
- } else if (ret > 0) {
- head = mid + 1;
- startprfx = matched;
- } else {
- back = mid - 1;
- endprfx = matched;
- }
- }
-
- return ERR_PTR(-ENOENT);
-}
-
-static struct page *find_target_block_classic(struct inode *dir,
- struct erofs_qstr *name,
- int *_ndirents)
-{
- unsigned int startprfx, endprfx;
- int head, back;
- struct address_space *const mapping = dir->i_mapping;
- struct page *candidate = ERR_PTR(-ENOENT);
-
- startprfx = endprfx = 0;
- head = 0;
- back = inode_datablocks(dir) - 1;
-
- while (head <= back) {
- const int mid = head + (back - head) / 2;
- struct page *page = read_mapping_page(mapping, mid, NULL);
-
- if (!IS_ERR(page)) {
- struct erofs_dirent *de = kmap_atomic(page);
- const int nameoff = nameoff_from_disk(de->nameoff,
- EROFS_BLKSIZ);
- const int ndirents = nameoff / sizeof(*de);
- int diff;
- unsigned int matched;
- struct erofs_qstr dname;
-
- if (unlikely(!ndirents)) {
- DBG_BUGON(1);
- kunmap_atomic(de);
- put_page(page);
- page = ERR_PTR(-EIO);
- goto out;
- }
-
- matched = min(startprfx, endprfx);
-
- dname.name = (u8 *)de + nameoff;
- if (ndirents == 1)
- dname.end = (u8 *)de + EROFS_BLKSIZ;
- else
- dname.end = (u8 *)de +
- nameoff_from_disk(de[1].nameoff,
- EROFS_BLKSIZ);
-
- /* string comparison without already matched prefix */
- diff = dirnamecmp(name, &dname, &matched);
- kunmap_atomic(de);
-
- if (unlikely(!diff)) {
- *_ndirents = 0;
- goto out;
- } else if (diff > 0) {
- head = mid + 1;
- startprfx = matched;
-
- if (!IS_ERR(candidate))
- put_page(candidate);
- candidate = page;
- *_ndirents = ndirents;
- } else {
- put_page(page);
-
- back = mid - 1;
- endprfx = matched;
- }
- continue;
- }
-out: /* free if the candidate is valid */
- if (!IS_ERR(candidate))
- put_page(candidate);
- return page;
- }
- return candidate;
-}
-
-int erofs_namei(struct inode *dir,
- struct qstr *name,
- erofs_nid_t *nid, unsigned int *d_type)
-{
- int ndirents;
- struct page *page;
- void *data;
- struct erofs_dirent *de;
- struct erofs_qstr qn;
-
- if (unlikely(!dir->i_size))
- return -ENOENT;
-
- qn.name = name->name;
- qn.end = name->name + name->len;
-
- ndirents = 0;
- page = find_target_block_classic(dir, &qn, &ndirents);
-
- if (IS_ERR(page))
- return PTR_ERR(page);
-
- data = kmap_atomic(page);
- /* the target page has been mapped */
- if (ndirents)
- de = find_target_dirent(&qn, data, EROFS_BLKSIZ, ndirents);
- else
- de = (struct erofs_dirent *)data;
-
- if (!IS_ERR(de)) {
- *nid = le64_to_cpu(de->nid);
- *d_type = de->file_type;
- }
-
- kunmap_atomic(data);
- put_page(page);
-
- return PTR_ERR_OR_ZERO(de);
-}
-
-/* NOTE: i_mutex is already held by vfs */
-static struct dentry *erofs_lookup(struct inode *dir,
- struct dentry *dentry,
- unsigned int flags)
-{
- int err;
- erofs_nid_t nid;
- unsigned int d_type;
- struct inode *inode;
-
- DBG_BUGON(!d_really_is_negative(dentry));
- /* dentry must be unhashed in lookup, no need to worry about */
- DBG_BUGON(!d_unhashed(dentry));
-
- trace_erofs_lookup(dir, dentry, flags);
-
- /* file name exceeds fs limit */
- if (unlikely(dentry->d_name.len > EROFS_NAME_LEN))
- return ERR_PTR(-ENAMETOOLONG);
-
- /* false uninitialized warnings on gcc 4.8.x */
- err = erofs_namei(dir, &dentry->d_name, &nid, &d_type);
-
- if (err == -ENOENT) {
- /* negative dentry */
- inode = NULL;
- } else if (unlikely(err)) {
- inode = ERR_PTR(err);
- } else {
- debugln("%s, %s (nid %llu) found, d_type %u", __func__,
- dentry->d_name.name, nid, d_type);
- inode = erofs_iget(dir->i_sb, nid, d_type == EROFS_FT_DIR);
- }
- return d_splice_alias(inode, dentry);
-}
-
-const struct inode_operations erofs_dir_iops = {
- .lookup = erofs_lookup,
- .getattr = erofs_getattr,
-#ifdef CONFIG_EROFS_FS_XATTR
- .listxattr = erofs_listxattr,
-#endif
- .get_acl = erofs_get_acl,
-};
-
diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c
deleted file mode 100644
index 54494412eba4..000000000000
--- a/drivers/staging/erofs/super.c
+++ /dev/null
@@ -1,701 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/super.c
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#include <linux/module.h>
-#include <linux/buffer_head.h>
-#include <linux/statfs.h>
-#include <linux/parser.h>
-#include <linux/seq_file.h>
-#include "internal.h"
-#include "xattr.h"
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/erofs.h>
-
-static struct kmem_cache *erofs_inode_cachep __read_mostly;
-
-static void init_once(void *ptr)
-{
- struct erofs_vnode *vi = ptr;
-
- inode_init_once(&vi->vfs_inode);
-}
-
-static int __init erofs_init_inode_cache(void)
-{
- erofs_inode_cachep = kmem_cache_create("erofs_inode",
- sizeof(struct erofs_vnode), 0,
- SLAB_RECLAIM_ACCOUNT,
- init_once);
-
- return erofs_inode_cachep ? 0 : -ENOMEM;
-}
-
-static void erofs_exit_inode_cache(void)
-{
- kmem_cache_destroy(erofs_inode_cachep);
-}
-
-static struct inode *alloc_inode(struct super_block *sb)
-{
- struct erofs_vnode *vi =
- kmem_cache_alloc(erofs_inode_cachep, GFP_KERNEL);
-
- if (!vi)
- return NULL;
-
- /* zero out everything except vfs_inode */
- memset(vi, 0, offsetof(struct erofs_vnode, vfs_inode));
- return &vi->vfs_inode;
-}
-
-static void free_inode(struct inode *inode)
-{
- struct erofs_vnode *vi = EROFS_V(inode);
-
- /* be careful RCU symlink path (see ext4_inode_info->i_data)! */
- if (is_inode_fast_symlink(inode))
- kfree(inode->i_link);
-
- kfree(vi->xattr_shared_xattrs);
-
- kmem_cache_free(erofs_inode_cachep, vi);
-}
-
-static bool check_layout_compatibility(struct super_block *sb,
- struct erofs_super_block *layout)
-{
- const unsigned int requirements = le32_to_cpu(layout->requirements);
-
- EROFS_SB(sb)->requirements = requirements;
-
- /* check if current kernel meets all mandatory requirements */
- if (requirements & (~EROFS_ALL_REQUIREMENTS)) {
- errln("unidentified requirements %x, please upgrade kernel version",
- requirements & ~EROFS_ALL_REQUIREMENTS);
- return false;
- }
- return true;
-}
-
-static int superblock_read(struct super_block *sb)
-{
- struct erofs_sb_info *sbi;
- struct buffer_head *bh;
- struct erofs_super_block *layout;
- unsigned int blkszbits;
- int ret;
-
- bh = sb_bread(sb, 0);
-
- if (!bh) {
- errln("cannot read erofs superblock");
- return -EIO;
- }
-
- sbi = EROFS_SB(sb);
- layout = (struct erofs_super_block *)((u8 *)bh->b_data
- + EROFS_SUPER_OFFSET);
-
- ret = -EINVAL;
- if (le32_to_cpu(layout->magic) != EROFS_SUPER_MAGIC_V1) {
- errln("cannot find valid erofs superblock");
- goto out;
- }
-
- blkszbits = layout->blkszbits;
- /* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
- if (unlikely(blkszbits != LOG_BLOCK_SIZE)) {
- errln("blksize %u isn't supported on this platform",
- 1 << blkszbits);
- goto out;
- }
-
- if (!check_layout_compatibility(sb, layout))
- goto out;
-
- sbi->blocks = le32_to_cpu(layout->blocks);
- sbi->meta_blkaddr = le32_to_cpu(layout->meta_blkaddr);
-#ifdef CONFIG_EROFS_FS_XATTR
- sbi->xattr_blkaddr = le32_to_cpu(layout->xattr_blkaddr);
-#endif
- sbi->islotbits = ffs(sizeof(struct erofs_inode_v1)) - 1;
-#ifdef CONFIG_EROFS_FS_ZIP
- /* TODO: clusterbits should be related to inode */
- sbi->clusterbits = blkszbits;
-
- if (1 << (sbi->clusterbits - PAGE_SHIFT) > Z_EROFS_CLUSTER_MAX_PAGES)
- errln("clusterbits %u is not supported on this kernel",
- sbi->clusterbits);
-#endif
-
- sbi->root_nid = le16_to_cpu(layout->root_nid);
- sbi->inos = le64_to_cpu(layout->inos);
-
- sbi->build_time = le64_to_cpu(layout->build_time);
- sbi->build_time_nsec = le32_to_cpu(layout->build_time_nsec);
-
- memcpy(&sb->s_uuid, layout->uuid, sizeof(layout->uuid));
- memcpy(sbi->volume_name, layout->volume_name,
- sizeof(layout->volume_name));
-
- ret = 0;
-out:
- brelse(bh);
- return ret;
-}
-
-#ifdef CONFIG_EROFS_FAULT_INJECTION
-const char *erofs_fault_name[FAULT_MAX] = {
- [FAULT_KMALLOC] = "kmalloc",
- [FAULT_READ_IO] = "read IO error",
-};
-
-static void __erofs_build_fault_attr(struct erofs_sb_info *sbi,
- unsigned int rate)
-{
- struct erofs_fault_info *ffi = &sbi->fault_info;
-
- if (rate) {
- atomic_set(&ffi->inject_ops, 0);
- ffi->inject_rate = rate;
- ffi->inject_type = (1 << FAULT_MAX) - 1;
- } else {
- memset(ffi, 0, sizeof(struct erofs_fault_info));
- }
-
- set_opt(sbi, FAULT_INJECTION);
-}
-
-static int erofs_build_fault_attr(struct erofs_sb_info *sbi,
- substring_t *args)
-{
- int rate = 0;
-
- if (args->from && match_int(args, &rate))
- return -EINVAL;
-
- __erofs_build_fault_attr(sbi, rate);
- return 0;
-}
-
-static unsigned int erofs_get_fault_rate(struct erofs_sb_info *sbi)
-{
- return sbi->fault_info.inject_rate;
-}
-#else
-static void __erofs_build_fault_attr(struct erofs_sb_info *sbi,
- unsigned int rate)
-{
-}
-
-static int erofs_build_fault_attr(struct erofs_sb_info *sbi,
- substring_t *args)
-{
- infoln("fault_injection options not supported");
- return 0;
-}
-
-static unsigned int erofs_get_fault_rate(struct erofs_sb_info *sbi)
-{
- return 0;
-}
-#endif
-
-static void default_options(struct erofs_sb_info *sbi)
-{
- /* set up some FS parameters */
-#ifdef CONFIG_EROFS_FS_ZIP
- sbi->max_sync_decompress_pages = DEFAULT_MAX_SYNC_DECOMPRESS_PAGES;
-#endif
-
-#ifdef CONFIG_EROFS_FS_XATTR
- set_opt(sbi, XATTR_USER);
-#endif
-
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
- set_opt(sbi, POSIX_ACL);
-#endif
-}
-
-enum {
- Opt_user_xattr,
- Opt_nouser_xattr,
- Opt_acl,
- Opt_noacl,
- Opt_fault_injection,
- Opt_err
-};
-
-static match_table_t erofs_tokens = {
- {Opt_user_xattr, "user_xattr"},
- {Opt_nouser_xattr, "nouser_xattr"},
- {Opt_acl, "acl"},
- {Opt_noacl, "noacl"},
- {Opt_fault_injection, "fault_injection=%u"},
- {Opt_err, NULL}
-};
-
-static int parse_options(struct super_block *sb, char *options)
-{
- substring_t args[MAX_OPT_ARGS];
- char *p;
- int err;
-
- if (!options)
- return 0;
-
- while ((p = strsep(&options, ","))) {
- int token;
-
- if (!*p)
- continue;
-
- args[0].to = args[0].from = NULL;
- token = match_token(p, erofs_tokens, args);
-
- switch (token) {
-#ifdef CONFIG_EROFS_FS_XATTR
- case Opt_user_xattr:
- set_opt(EROFS_SB(sb), XATTR_USER);
- break;
- case Opt_nouser_xattr:
- clear_opt(EROFS_SB(sb), XATTR_USER);
- break;
-#else
- case Opt_user_xattr:
- infoln("user_xattr options not supported");
- break;
- case Opt_nouser_xattr:
- infoln("nouser_xattr options not supported");
- break;
-#endif
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
- case Opt_acl:
- set_opt(EROFS_SB(sb), POSIX_ACL);
- break;
- case Opt_noacl:
- clear_opt(EROFS_SB(sb), POSIX_ACL);
- break;
-#else
- case Opt_acl:
- infoln("acl options not supported");
- break;
- case Opt_noacl:
- infoln("noacl options not supported");
- break;
-#endif
- case Opt_fault_injection:
- err = erofs_build_fault_attr(EROFS_SB(sb), args);
- if (err)
- return err;
- break;
-
- default:
- errln("Unrecognized mount option \"%s\" "
- "or missing value", p);
- return -EINVAL;
- }
- }
- return 0;
-}
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
-
-static const struct address_space_operations managed_cache_aops;
-
-static int managed_cache_releasepage(struct page *page, gfp_t gfp_mask)
-{
- int ret = 1; /* 0 - busy */
- struct address_space *const mapping = page->mapping;
-
- DBG_BUGON(!PageLocked(page));
- DBG_BUGON(mapping->a_ops != &managed_cache_aops);
-
- if (PagePrivate(page))
- ret = erofs_try_to_free_cached_page(mapping, page);
-
- return ret;
-}
-
-static void managed_cache_invalidatepage(struct page *page,
- unsigned int offset,
- unsigned int length)
-{
- const unsigned int stop = length + offset;
-
- DBG_BUGON(!PageLocked(page));
-
- /* Check for potential overflow in debug mode */
- DBG_BUGON(stop > PAGE_SIZE || stop < length);
-
- if (offset == 0 && stop == PAGE_SIZE)
- while (!managed_cache_releasepage(page, GFP_NOFS))
- cond_resched();
-}
-
-static const struct address_space_operations managed_cache_aops = {
- .releasepage = managed_cache_releasepage,
- .invalidatepage = managed_cache_invalidatepage,
-};
-
-static struct inode *erofs_init_managed_cache(struct super_block *sb)
-{
- struct inode *inode = new_inode(sb);
-
- if (unlikely(!inode))
- return ERR_PTR(-ENOMEM);
-
- set_nlink(inode, 1);
- inode->i_size = OFFSET_MAX;
-
- inode->i_mapping->a_ops = &managed_cache_aops;
- mapping_set_gfp_mask(inode->i_mapping,
- GFP_NOFS | __GFP_HIGHMEM |
- __GFP_MOVABLE | __GFP_NOFAIL);
- return inode;
-}
-
-#endif
-
-static int erofs_read_super(struct super_block *sb,
- const char *dev_name,
- void *data, int silent)
-{
- struct inode *inode;
- struct erofs_sb_info *sbi;
- int err = -EINVAL;
-
- infoln("read_super, device -> %s", dev_name);
- infoln("options -> %s", (char *)data);
-
- if (unlikely(!sb_set_blocksize(sb, EROFS_BLKSIZ))) {
- errln("failed to set erofs blksize");
- goto err;
- }
-
- sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
- if (unlikely(!sbi)) {
- err = -ENOMEM;
- goto err;
- }
- sb->s_fs_info = sbi;
-
- err = superblock_read(sb);
- if (err)
- goto err_sbread;
-
- sb->s_magic = EROFS_SUPER_MAGIC;
- sb->s_flags |= SB_RDONLY | SB_NOATIME;
- sb->s_maxbytes = MAX_LFS_FILESIZE;
- sb->s_time_gran = 1;
-
- sb->s_op = &erofs_sops;
-
-#ifdef CONFIG_EROFS_FS_XATTR
- sb->s_xattr = erofs_xattr_handlers;
-#endif
-
- /* set erofs default mount options */
- default_options(sbi);
-
- err = parse_options(sb, data);
- if (err)
- goto err_parseopt;
-
- if (!silent)
- infoln("root inode @ nid %llu", ROOT_NID(sbi));
-
- if (test_opt(sbi, POSIX_ACL))
- sb->s_flags |= SB_POSIXACL;
- else
- sb->s_flags &= ~SB_POSIXACL;
-
-#ifdef CONFIG_EROFS_FS_ZIP
- INIT_RADIX_TREE(&sbi->workstn_tree, GFP_ATOMIC);
-#endif
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
- sbi->managed_cache = erofs_init_managed_cache(sb);
- if (IS_ERR(sbi->managed_cache)) {
- err = PTR_ERR(sbi->managed_cache);
- goto err_init_managed_cache;
- }
-#endif
-
- /* get the root inode */
- inode = erofs_iget(sb, ROOT_NID(sbi), true);
- if (IS_ERR(inode)) {
- err = PTR_ERR(inode);
- goto err_iget;
- }
-
- if (!S_ISDIR(inode->i_mode)) {
- errln("rootino(nid %llu) is not a directory(i_mode %o)",
- ROOT_NID(sbi), inode->i_mode);
- err = -EINVAL;
- iput(inode);
- goto err_iget;
- }
-
- sb->s_root = d_make_root(inode);
- if (!sb->s_root) {
- err = -ENOMEM;
- goto err_iget;
- }
-
- /* save the device name to sbi */
- sbi->dev_name = __getname();
- if (!sbi->dev_name) {
- err = -ENOMEM;
- goto err_devname;
- }
-
- snprintf(sbi->dev_name, PATH_MAX, "%s", dev_name);
- sbi->dev_name[PATH_MAX - 1] = '\0';
-
- erofs_register_super(sb);
-
- if (!silent)
- infoln("mounted on %s with opts: %s.", dev_name,
- (char *)data);
- return 0;
- /*
- * please add a label for each exit point and use
- * the following name convention, thus new features
- * can be integrated easily without renaming labels.
- */
-err_devname:
- dput(sb->s_root);
- sb->s_root = NULL;
-err_iget:
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
- iput(sbi->managed_cache);
-err_init_managed_cache:
-#endif
-err_parseopt:
-err_sbread:
- sb->s_fs_info = NULL;
- kfree(sbi);
-err:
- return err;
-}
-
-/*
- * could be triggered after deactivate_locked_super()
- * is called, thus including umount and failed to initialize.
- */
-static void erofs_put_super(struct super_block *sb)
-{
- struct erofs_sb_info *sbi = EROFS_SB(sb);
-
- /* for cases which are failed in "read_super" */
- if (!sbi)
- return;
-
- WARN_ON(sb->s_magic != EROFS_SUPER_MAGIC);
-
- infoln("unmounted for %s", sbi->dev_name);
- __putname(sbi->dev_name);
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
- iput(sbi->managed_cache);
-#endif
-
- mutex_lock(&sbi->umount_mutex);
-
-#ifdef CONFIG_EROFS_FS_ZIP
- /* clean up the compression space of this sb */
- erofs_shrink_workstation(EROFS_SB(sb), ~0UL, true);
-#endif
-
- erofs_unregister_super(sb);
- mutex_unlock(&sbi->umount_mutex);
-
- kfree(sbi);
- sb->s_fs_info = NULL;
-}
-
-
-struct erofs_mount_private {
- const char *dev_name;
- char *options;
-};
-
-/* support mount_bdev() with options */
-static int erofs_fill_super(struct super_block *sb,
- void *_priv, int silent)
-{
- struct erofs_mount_private *priv = _priv;
-
- return erofs_read_super(sb, priv->dev_name,
- priv->options, silent);
-}
-
-static struct dentry *erofs_mount(
- struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
-{
- struct erofs_mount_private priv = {
- .dev_name = dev_name,
- .options = data
- };
-
- return mount_bdev(fs_type, flags, dev_name,
- &priv, erofs_fill_super);
-}
-
-static void erofs_kill_sb(struct super_block *sb)
-{
- kill_block_super(sb);
-}
-
-static struct file_system_type erofs_fs_type = {
- .owner = THIS_MODULE,
- .name = "erofs",
- .mount = erofs_mount,
- .kill_sb = erofs_kill_sb,
- .fs_flags = FS_REQUIRES_DEV,
-};
-MODULE_ALIAS_FS("erofs");
-
-static int __init erofs_module_init(void)
-{
- int err;
-
- erofs_check_ondisk_layout_definitions();
- infoln("initializing erofs " EROFS_VERSION);
-
- err = erofs_init_inode_cache();
- if (err)
- goto icache_err;
-
- err = register_shrinker(&erofs_shrinker_info);
- if (err)
- goto shrinker_err;
-
- err = z_erofs_init_zip_subsystem();
- if (err)
- goto zip_err;
-
- err = register_filesystem(&erofs_fs_type);
- if (err)
- goto fs_err;
-
- infoln("successfully to initialize erofs");
- return 0;
-
-fs_err:
- z_erofs_exit_zip_subsystem();
-zip_err:
- unregister_shrinker(&erofs_shrinker_info);
-shrinker_err:
- erofs_exit_inode_cache();
-icache_err:
- return err;
-}
-
-static void __exit erofs_module_exit(void)
-{
- unregister_filesystem(&erofs_fs_type);
- z_erofs_exit_zip_subsystem();
- unregister_shrinker(&erofs_shrinker_info);
- erofs_exit_inode_cache();
- infoln("successfully finalize erofs");
-}
-
-/* get filesystem statistics */
-static int erofs_statfs(struct dentry *dentry, struct kstatfs *buf)
-{
- struct super_block *sb = dentry->d_sb;
- struct erofs_sb_info *sbi = EROFS_SB(sb);
- u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
-
- buf->f_type = sb->s_magic;
- buf->f_bsize = EROFS_BLKSIZ;
- buf->f_blocks = sbi->blocks;
- buf->f_bfree = buf->f_bavail = 0;
-
- buf->f_files = ULLONG_MAX;
- buf->f_ffree = ULLONG_MAX - sbi->inos;
-
- buf->f_namelen = EROFS_NAME_LEN;
-
- buf->f_fsid.val[0] = (u32)id;
- buf->f_fsid.val[1] = (u32)(id >> 32);
- return 0;
-}
-
-static int erofs_show_options(struct seq_file *seq, struct dentry *root)
-{
- struct erofs_sb_info *sbi __maybe_unused = EROFS_SB(root->d_sb);
-
-#ifdef CONFIG_EROFS_FS_XATTR
- if (test_opt(sbi, XATTR_USER))
- seq_puts(seq, ",user_xattr");
- else
- seq_puts(seq, ",nouser_xattr");
-#endif
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
- if (test_opt(sbi, POSIX_ACL))
- seq_puts(seq, ",acl");
- else
- seq_puts(seq, ",noacl");
-#endif
- if (test_opt(sbi, FAULT_INJECTION))
- seq_printf(seq, ",fault_injection=%u",
- erofs_get_fault_rate(sbi));
- return 0;
-}
-
-static int erofs_remount(struct super_block *sb, int *flags, char *data)
-{
- struct erofs_sb_info *sbi = EROFS_SB(sb);
- unsigned int org_mnt_opt = sbi->mount_opt;
- unsigned int org_inject_rate = erofs_get_fault_rate(sbi);
- int err;
-
- DBG_BUGON(!sb_rdonly(sb));
- err = parse_options(sb, data);
- if (err)
- goto out;
-
- if (test_opt(sbi, POSIX_ACL))
- sb->s_flags |= SB_POSIXACL;
- else
- sb->s_flags &= ~SB_POSIXACL;
-
- *flags |= SB_RDONLY;
- return 0;
-out:
- __erofs_build_fault_attr(sbi, org_inject_rate);
- sbi->mount_opt = org_mnt_opt;
-
- return err;
-}
-
-const struct super_operations erofs_sops = {
- .put_super = erofs_put_super,
- .alloc_inode = alloc_inode,
- .free_inode = free_inode,
- .statfs = erofs_statfs,
- .show_options = erofs_show_options,
- .remount_fs = erofs_remount,
-};
-
-module_init(erofs_module_init);
-module_exit(erofs_module_exit);
-
-MODULE_DESCRIPTION("Enhanced ROM File System");
-MODULE_AUTHOR("Gao Xiang, Yu Chao, Miao Xie, CONSUMER BG, HUAWEI Inc.");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/staging/erofs/unzip_pagevec.h b/drivers/staging/erofs/unzip_pagevec.h
deleted file mode 100644
index 7af0ba8d8495..000000000000
--- a/drivers/staging/erofs/unzip_pagevec.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * linux/drivers/staging/erofs/unzip_pagevec.h
- *
- * Copyright (C) 2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#ifndef __EROFS_UNZIP_PAGEVEC_H
-#define __EROFS_UNZIP_PAGEVEC_H
-
-#include <linux/tagptr.h>
-
-/* page type in pagevec for unzip subsystem */
-enum z_erofs_page_type {
- /* including Z_EROFS_VLE_PAGE_TAIL_EXCLUSIVE */
- Z_EROFS_PAGE_TYPE_EXCLUSIVE,
-
- Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED,
-
- Z_EROFS_VLE_PAGE_TYPE_HEAD,
- Z_EROFS_VLE_PAGE_TYPE_MAX
-};
-
-extern void __compiletime_error("Z_EROFS_PAGE_TYPE_EXCLUSIVE != 0")
- __bad_page_type_exclusive(void);
-
-/* pagevec tagged pointer */
-typedef tagptr2_t erofs_vtptr_t;
-
-/* pagevec collector */
-struct z_erofs_pagevec_ctor {
- struct page *curr, *next;
- erofs_vtptr_t *pages;
-
- unsigned int nr, index;
-};
-
-static inline void z_erofs_pagevec_ctor_exit(struct z_erofs_pagevec_ctor *ctor,
- bool atomic)
-{
- if (!ctor->curr)
- return;
-
- if (atomic)
- kunmap_atomic(ctor->pages);
- else
- kunmap(ctor->curr);
-}
-
-static inline struct page *
-z_erofs_pagevec_ctor_next_page(struct z_erofs_pagevec_ctor *ctor,
- unsigned nr)
-{
- unsigned index;
-
- /* keep away from occupied pages */
- if (ctor->next)
- return ctor->next;
-
- for (index = 0; index < nr; ++index) {
- const erofs_vtptr_t t = ctor->pages[index];
- const unsigned tags = tagptr_unfold_tags(t);
-
- if (tags == Z_EROFS_PAGE_TYPE_EXCLUSIVE)
- return tagptr_unfold_ptr(t);
- }
- DBG_BUGON(nr >= ctor->nr);
- return NULL;
-}
-
-static inline void
-z_erofs_pagevec_ctor_pagedown(struct z_erofs_pagevec_ctor *ctor,
- bool atomic)
-{
- struct page *next = z_erofs_pagevec_ctor_next_page(ctor, ctor->nr);
-
- z_erofs_pagevec_ctor_exit(ctor, atomic);
-
- ctor->curr = next;
- ctor->next = NULL;
- ctor->pages = atomic ?
- kmap_atomic(ctor->curr) : kmap(ctor->curr);
-
- ctor->nr = PAGE_SIZE / sizeof(struct page *);
- ctor->index = 0;
-}
-
-static inline void z_erofs_pagevec_ctor_init(struct z_erofs_pagevec_ctor *ctor,
- unsigned nr,
- erofs_vtptr_t *pages, unsigned i)
-{
- ctor->nr = nr;
- ctor->curr = ctor->next = NULL;
- ctor->pages = pages;
-
- if (i >= nr) {
- i -= nr;
- z_erofs_pagevec_ctor_pagedown(ctor, false);
- while (i > ctor->nr) {
- i -= ctor->nr;
- z_erofs_pagevec_ctor_pagedown(ctor, false);
- }
- }
-
- ctor->next = z_erofs_pagevec_ctor_next_page(ctor, i);
- ctor->index = i;
-}
-
-static inline bool
-z_erofs_pagevec_ctor_enqueue(struct z_erofs_pagevec_ctor *ctor,
- struct page *page,
- enum z_erofs_page_type type,
- bool *occupied)
-{
- *occupied = false;
- if (unlikely(!ctor->next && type))
- if (ctor->index + 1 == ctor->nr)
- return false;
-
- if (unlikely(ctor->index >= ctor->nr))
- z_erofs_pagevec_ctor_pagedown(ctor, false);
-
- /* exclusive page type must be 0 */
- if (Z_EROFS_PAGE_TYPE_EXCLUSIVE != (uintptr_t)NULL)
- __bad_page_type_exclusive();
-
- /* should remind that collector->next never equal to 1, 2 */
- if (type == (uintptr_t)ctor->next) {
- ctor->next = page;
- *occupied = true;
- }
-
- ctor->pages[ctor->index++] =
- tagptr_fold(erofs_vtptr_t, page, type);
- return true;
-}
-
-static inline struct page *
-z_erofs_pagevec_ctor_dequeue(struct z_erofs_pagevec_ctor *ctor,
- enum z_erofs_page_type *type)
-{
- erofs_vtptr_t t;
-
- if (unlikely(ctor->index >= ctor->nr)) {
- DBG_BUGON(!ctor->next);
- z_erofs_pagevec_ctor_pagedown(ctor, true);
- }
-
- t = ctor->pages[ctor->index];
-
- *type = tagptr_unfold_tags(t);
-
- /* should remind that collector->next never equal to 1, 2 */
- if (*type == (uintptr_t)ctor->next)
- ctor->next = tagptr_unfold_ptr(t);
-
- ctor->pages[ctor->index++] =
- tagptr_fold(erofs_vtptr_t, NULL, 0);
-
- return tagptr_unfold_ptr(t);
-}
-
-#endif
-
diff --git a/drivers/staging/erofs/unzip_vle.c b/drivers/staging/erofs/unzip_vle.c
deleted file mode 100644
index f0dab81ff816..000000000000
--- a/drivers/staging/erofs/unzip_vle.c
+++ /dev/null
@@ -1,1591 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/unzip_vle.c
- *
- * Copyright (C) 2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#include "unzip_vle.h"
-#include "compress.h"
-#include <linux/prefetch.h>
-
-#include <trace/events/erofs.h>
-
-/*
- * a compressed_pages[] placeholder in order to avoid
- * being filled with file pages for in-place decompression.
- */
-#define PAGE_UNALLOCATED ((void *)0x5F0E4B1D)
-
-/* how to allocate cached pages for a workgroup */
-enum z_erofs_cache_alloctype {
- DONTALLOC, /* don't allocate any cached pages */
- DELAYEDALLOC, /* delayed allocation (at the time of submitting io) */
-};
-
-/*
- * tagged pointer with 1-bit tag for all compressed pages
- * tag 0 - the page is just found with an extra page reference
- */
-typedef tagptr1_t compressed_page_t;
-
-#define tag_compressed_page_justfound(page) \
- tagptr_fold(compressed_page_t, page, 1)
-
-static struct workqueue_struct *z_erofs_workqueue __read_mostly;
-static struct kmem_cache *z_erofs_workgroup_cachep __read_mostly;
-
-void z_erofs_exit_zip_subsystem(void)
-{
- destroy_workqueue(z_erofs_workqueue);
- kmem_cache_destroy(z_erofs_workgroup_cachep);
-}
-
-static inline int init_unzip_workqueue(void)
-{
- const unsigned int onlinecpus = num_possible_cpus();
-
- /*
- * we don't need too many threads, limiting threads
- * could improve scheduling performance.
- */
- z_erofs_workqueue =
- alloc_workqueue("erofs_unzipd",
- WQ_UNBOUND | WQ_HIGHPRI | WQ_CPU_INTENSIVE,
- onlinecpus + onlinecpus / 4);
-
- return z_erofs_workqueue ? 0 : -ENOMEM;
-}
-
-static void init_once(void *ptr)
-{
- struct z_erofs_vle_workgroup *grp = ptr;
- struct z_erofs_vle_work *const work =
- z_erofs_vle_grab_primary_work(grp);
- unsigned int i;
-
- mutex_init(&work->lock);
- work->nr_pages = 0;
- work->vcnt = 0;
- for (i = 0; i < Z_EROFS_CLUSTER_MAX_PAGES; ++i)
- grp->compressed_pages[i] = NULL;
-}
-
-static void init_always(struct z_erofs_vle_workgroup *grp)
-{
- struct z_erofs_vle_work *const work =
- z_erofs_vle_grab_primary_work(grp);
-
- atomic_set(&grp->obj.refcount, 1);
- grp->flags = 0;
-
- DBG_BUGON(work->nr_pages);
- DBG_BUGON(work->vcnt);
-}
-
-int __init z_erofs_init_zip_subsystem(void)
-{
- z_erofs_workgroup_cachep =
- kmem_cache_create("erofs_compress",
- Z_EROFS_WORKGROUP_SIZE, 0,
- SLAB_RECLAIM_ACCOUNT, init_once);
-
- if (z_erofs_workgroup_cachep) {
- if (!init_unzip_workqueue())
- return 0;
-
- kmem_cache_destroy(z_erofs_workgroup_cachep);
- }
- return -ENOMEM;
-}
-
-enum z_erofs_vle_work_role {
- Z_EROFS_VLE_WORK_SECONDARY,
- Z_EROFS_VLE_WORK_PRIMARY,
- /*
- * The current work was the tail of an exist chain, and the previous
- * processed chained works are all decided to be hooked up to it.
- * A new chain should be created for the remaining unprocessed works,
- * therefore different from Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED,
- * the next work cannot reuse the whole page in the following scenario:
- * ________________________________________________________________
- * | tail (partial) page | head (partial) page |
- * | (belongs to the next work) | (belongs to the current work) |
- * |_______PRIMARY_FOLLOWED_______|________PRIMARY_HOOKED___________|
- */
- Z_EROFS_VLE_WORK_PRIMARY_HOOKED,
- /*
- * The current work has been linked with the processed chained works,
- * and could be also linked with the potential remaining works, which
- * means if the processing page is the tail partial page of the work,
- * the current work can safely use the whole page (since the next work
- * is under control) for in-place decompression, as illustrated below:
- * ________________________________________________________________
- * | tail (partial) page | head (partial) page |
- * | (of the current work) | (of the previous work) |
- * | PRIMARY_FOLLOWED or | |
- * |_____PRIMARY_HOOKED____|____________PRIMARY_FOLLOWED____________|
- *
- * [ (*) the above page can be used for the current work itself. ]
- */
- Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED,
- Z_EROFS_VLE_WORK_MAX
-};
-
-struct z_erofs_vle_work_builder {
- enum z_erofs_vle_work_role role;
- /*
- * 'hosted = false' means that the current workgroup doesn't belong to
- * the owned chained workgroups. In the other words, it is none of our
- * business to submit this workgroup.
- */
- bool hosted;
-
- struct z_erofs_vle_workgroup *grp;
- struct z_erofs_vle_work *work;
- struct z_erofs_pagevec_ctor vector;
-
- /* pages used for reading the compressed data */
- struct page **compressed_pages;
- unsigned int compressed_deficit;
-};
-
-#define VLE_WORK_BUILDER_INIT() \
- { .work = NULL, .role = Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED }
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
-static void preload_compressed_pages(struct z_erofs_vle_work_builder *bl,
- struct address_space *mc,
- pgoff_t index,
- unsigned int clusterpages,
- enum z_erofs_cache_alloctype type,
- struct list_head *pagepool,
- gfp_t gfp)
-{
- struct page **const pages = bl->compressed_pages;
- const unsigned int remaining = bl->compressed_deficit;
- bool standalone = true;
- unsigned int i, j = 0;
-
- if (bl->role < Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED)
- return;
-
- gfp = mapping_gfp_constraint(mc, gfp) & ~__GFP_RECLAIM;
-
- index += clusterpages - remaining;
-
- for (i = 0; i < remaining; ++i) {
- struct page *page;
- compressed_page_t t;
-
- /* the compressed page was loaded before */
- if (READ_ONCE(pages[i]))
- continue;
-
- page = find_get_page(mc, index + i);
-
- if (page) {
- t = tag_compressed_page_justfound(page);
- } else if (type == DELAYEDALLOC) {
- t = tagptr_init(compressed_page_t, PAGE_UNALLOCATED);
- } else { /* DONTALLOC */
- if (standalone)
- j = i;
- standalone = false;
- continue;
- }
-
- if (!cmpxchg_relaxed(&pages[i], NULL, tagptr_cast_ptr(t)))
- continue;
-
- if (page)
- put_page(page);
- }
- bl->compressed_pages += j;
- bl->compressed_deficit = remaining - j;
-
- if (standalone)
- bl->role = Z_EROFS_VLE_WORK_PRIMARY;
-}
-
-/* called by erofs_shrinker to get rid of all compressed_pages */
-int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
- struct erofs_workgroup *egrp)
-{
- struct z_erofs_vle_workgroup *const grp =
- container_of(egrp, struct z_erofs_vle_workgroup, obj);
- struct address_space *const mapping = MNGD_MAPPING(sbi);
- const int clusterpages = erofs_clusterpages(sbi);
- int i;
-
- /*
- * refcount of workgroup is now freezed as 1,
- * therefore no need to worry about available decompression users.
- */
- for (i = 0; i < clusterpages; ++i) {
- struct page *page = grp->compressed_pages[i];
-
- if (!page || page->mapping != mapping)
- continue;
-
- /* block other users from reclaiming or migrating the page */
- if (!trylock_page(page))
- return -EBUSY;
-
- /* barrier is implied in the following 'unlock_page' */
- WRITE_ONCE(grp->compressed_pages[i], NULL);
-
- set_page_private(page, 0);
- ClearPagePrivate(page);
-
- unlock_page(page);
- put_page(page);
- }
- return 0;
-}
-
-int erofs_try_to_free_cached_page(struct address_space *mapping,
- struct page *page)
-{
- struct erofs_sb_info *const sbi = EROFS_SB(mapping->host->i_sb);
- const unsigned int clusterpages = erofs_clusterpages(sbi);
- struct z_erofs_vle_workgroup *const grp = (void *)page_private(page);
- int ret = 0; /* 0 - busy */
-
- if (erofs_workgroup_try_to_freeze(&grp->obj, 1)) {
- unsigned int i;
-
- for (i = 0; i < clusterpages; ++i) {
- if (grp->compressed_pages[i] == page) {
- WRITE_ONCE(grp->compressed_pages[i], NULL);
- ret = 1;
- break;
- }
- }
- erofs_workgroup_unfreeze(&grp->obj, 1);
-
- if (ret) {
- ClearPagePrivate(page);
- put_page(page);
- }
- }
- return ret;
-}
-#else
-static void preload_compressed_pages(struct z_erofs_vle_work_builder *bl,
- struct address_space *mc,
- pgoff_t index,
- unsigned int clusterpages,
- enum z_erofs_cache_alloctype type,
- struct list_head *pagepool,
- gfp_t gfp)
-{
- /* nowhere to load compressed pages from */
-}
-#endif
-
-/* page_type must be Z_EROFS_PAGE_TYPE_EXCLUSIVE */
-static inline bool try_to_reuse_as_compressed_page(
- struct z_erofs_vle_work_builder *b,
- struct page *page)
-{
- while (b->compressed_deficit) {
- --b->compressed_deficit;
- if (!cmpxchg(b->compressed_pages++, NULL, page))
- return true;
- }
-
- return false;
-}
-
-/* callers must be with work->lock held */
-static int z_erofs_vle_work_add_page(
- struct z_erofs_vle_work_builder *builder,
- struct page *page,
- enum z_erofs_page_type type)
-{
- int ret;
- bool occupied;
-
- /* give priority for the compressed data storage */
- if (builder->role >= Z_EROFS_VLE_WORK_PRIMARY &&
- type == Z_EROFS_PAGE_TYPE_EXCLUSIVE &&
- try_to_reuse_as_compressed_page(builder, page))
- return 0;
-
- ret = z_erofs_pagevec_ctor_enqueue(&builder->vector,
- page, type, &occupied);
- builder->work->vcnt += (unsigned int)ret;
-
- return ret ? 0 : -EAGAIN;
-}
-
-static enum z_erofs_vle_work_role
-try_to_claim_workgroup(struct z_erofs_vle_workgroup *grp,
- z_erofs_vle_owned_workgrp_t *owned_head,
- bool *hosted)
-{
- DBG_BUGON(*hosted);
-
- /* let's claim these following types of workgroup */
-retry:
- if (grp->next == Z_EROFS_VLE_WORKGRP_NIL) {
- /* type 1, nil workgroup */
- if (cmpxchg(&grp->next, Z_EROFS_VLE_WORKGRP_NIL,
- *owned_head) != Z_EROFS_VLE_WORKGRP_NIL)
- goto retry;
-
- *owned_head = &grp->next;
- *hosted = true;
- /* lucky, I am the followee :) */
- return Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED;
-
- } else if (grp->next == Z_EROFS_VLE_WORKGRP_TAIL) {
- /*
- * type 2, link to the end of a existing open chain,
- * be careful that its submission itself is governed
- * by the original owned chain.
- */
- if (cmpxchg(&grp->next, Z_EROFS_VLE_WORKGRP_TAIL,
- *owned_head) != Z_EROFS_VLE_WORKGRP_TAIL)
- goto retry;
- *owned_head = Z_EROFS_VLE_WORKGRP_TAIL;
- return Z_EROFS_VLE_WORK_PRIMARY_HOOKED;
- }
-
- return Z_EROFS_VLE_WORK_PRIMARY; /* :( better luck next time */
-}
-
-struct z_erofs_vle_work_finder {
- struct super_block *sb;
- pgoff_t idx;
- unsigned int pageofs;
-
- struct z_erofs_vle_workgroup **grp_ret;
- enum z_erofs_vle_work_role *role;
- z_erofs_vle_owned_workgrp_t *owned_head;
- bool *hosted;
-};
-
-static struct z_erofs_vle_work *
-z_erofs_vle_work_lookup(const struct z_erofs_vle_work_finder *f)
-{
- bool tag, primary;
- struct erofs_workgroup *egrp;
- struct z_erofs_vle_workgroup *grp;
- struct z_erofs_vle_work *work;
-
- egrp = erofs_find_workgroup(f->sb, f->idx, &tag);
- if (!egrp) {
- *f->grp_ret = NULL;
- return NULL;
- }
-
- grp = container_of(egrp, struct z_erofs_vle_workgroup, obj);
- *f->grp_ret = grp;
-
- work = z_erofs_vle_grab_work(grp, f->pageofs);
- /* if multiref is disabled, `primary' is always true */
- primary = true;
-
- DBG_BUGON(work->pageofs != f->pageofs);
-
- /*
- * lock must be taken first to avoid grp->next == NIL between
- * claiming workgroup and adding pages:
- * grp->next != NIL
- * grp->next = NIL
- * mutex_unlock_all
- * mutex_lock(&work->lock)
- * add all pages to pagevec
- *
- * [correct locking case 1]:
- * mutex_lock(grp->work[a])
- * ...
- * mutex_lock(grp->work[b]) mutex_lock(grp->work[c])
- * ... *role = SECONDARY
- * add all pages to pagevec
- * ...
- * mutex_unlock(grp->work[c])
- * mutex_lock(grp->work[c])
- * ...
- * grp->next = NIL
- * mutex_unlock_all
- *
- * [correct locking case 2]:
- * mutex_lock(grp->work[b])
- * ...
- * mutex_lock(grp->work[a])
- * ...
- * mutex_lock(grp->work[c])
- * ...
- * grp->next = NIL
- * mutex_unlock_all
- * mutex_lock(grp->work[a])
- * *role = PRIMARY_OWNER
- * add all pages to pagevec
- * ...
- */
- mutex_lock(&work->lock);
-
- *f->hosted = false;
- if (!primary)
- *f->role = Z_EROFS_VLE_WORK_SECONDARY;
- else /* claim the workgroup if possible */
- *f->role = try_to_claim_workgroup(grp, f->owned_head,
- f->hosted);
- return work;
-}
-
-static struct z_erofs_vle_work *
-z_erofs_vle_work_register(const struct z_erofs_vle_work_finder *f,
- struct erofs_map_blocks *map)
-{
- bool gnew = false;
- struct z_erofs_vle_workgroup *grp = *f->grp_ret;
- struct z_erofs_vle_work *work;
-
- /* if multiref is disabled, grp should never be nullptr */
- if (unlikely(grp)) {
- DBG_BUGON(1);
- return ERR_PTR(-EINVAL);
- }
-
- /* no available workgroup, let's allocate one */
- grp = kmem_cache_alloc(z_erofs_workgroup_cachep, GFP_NOFS);
- if (unlikely(!grp))
- return ERR_PTR(-ENOMEM);
-
- init_always(grp);
- grp->obj.index = f->idx;
- grp->llen = map->m_llen;
-
- z_erofs_vle_set_workgrp_fmt(grp, (map->m_flags & EROFS_MAP_ZIPPED) ?
- Z_EROFS_VLE_WORKGRP_FMT_LZ4 :
- Z_EROFS_VLE_WORKGRP_FMT_PLAIN);
-
- if (map->m_flags & EROFS_MAP_FULL_MAPPED)
- grp->flags |= Z_EROFS_VLE_WORKGRP_FULL_LENGTH;
-
- /* new workgrps have been claimed as type 1 */
- WRITE_ONCE(grp->next, *f->owned_head);
- /* primary and followed work for all new workgrps */
- *f->role = Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED;
- /* it should be submitted by ourselves */
- *f->hosted = true;
-
- gnew = true;
- work = z_erofs_vle_grab_primary_work(grp);
- work->pageofs = f->pageofs;
-
- /*
- * lock all primary followed works before visible to others
- * and mutex_trylock *never* fails for a new workgroup.
- */
- mutex_trylock(&work->lock);
-
- if (gnew) {
- int err = erofs_register_workgroup(f->sb, &grp->obj, 0);
-
- if (err) {
- mutex_unlock(&work->lock);
- kmem_cache_free(z_erofs_workgroup_cachep, grp);
- return ERR_PTR(-EAGAIN);
- }
- }
-
- *f->owned_head = &grp->next;
- *f->grp_ret = grp;
- return work;
-}
-
-#define builder_is_hooked(builder) \
- ((builder)->role >= Z_EROFS_VLE_WORK_PRIMARY_HOOKED)
-
-#define builder_is_followed(builder) \
- ((builder)->role >= Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED)
-
-static int z_erofs_vle_work_iter_begin(struct z_erofs_vle_work_builder *builder,
- struct super_block *sb,
- struct erofs_map_blocks *map,
- z_erofs_vle_owned_workgrp_t *owned_head)
-{
- const unsigned int clusterpages = erofs_clusterpages(EROFS_SB(sb));
- struct z_erofs_vle_workgroup *grp;
- const struct z_erofs_vle_work_finder finder = {
- .sb = sb,
- .idx = erofs_blknr(map->m_pa),
- .pageofs = map->m_la & ~PAGE_MASK,
- .grp_ret = &grp,
- .role = &builder->role,
- .owned_head = owned_head,
- .hosted = &builder->hosted
- };
- struct z_erofs_vle_work *work;
-
- DBG_BUGON(builder->work);
-
- /* must be Z_EROFS_WORK_TAIL or the next chained work */
- DBG_BUGON(*owned_head == Z_EROFS_VLE_WORKGRP_NIL);
- DBG_BUGON(*owned_head == Z_EROFS_VLE_WORKGRP_TAIL_CLOSED);
-
- DBG_BUGON(erofs_blkoff(map->m_pa));
-
-repeat:
- work = z_erofs_vle_work_lookup(&finder);
- if (work) {
- unsigned int orig_llen;
-
- /* increase workgroup `llen' if needed */
- while ((orig_llen = READ_ONCE(grp->llen)) < map->m_llen &&
- orig_llen != cmpxchg_relaxed(&grp->llen,
- orig_llen, map->m_llen))
- cpu_relax();
- goto got_it;
- }
-
- work = z_erofs_vle_work_register(&finder, map);
- if (unlikely(work == ERR_PTR(-EAGAIN)))
- goto repeat;
-
- if (IS_ERR(work))
- return PTR_ERR(work);
-got_it:
- z_erofs_pagevec_ctor_init(&builder->vector, Z_EROFS_NR_INLINE_PAGEVECS,
- work->pagevec, work->vcnt);
-
- if (builder->role >= Z_EROFS_VLE_WORK_PRIMARY) {
- /* enable possibly in-place decompression */
- builder->compressed_pages = grp->compressed_pages;
- builder->compressed_deficit = clusterpages;
- } else {
- builder->compressed_pages = NULL;
- builder->compressed_deficit = 0;
- }
-
- builder->grp = grp;
- builder->work = work;
- return 0;
-}
-
-/*
- * keep in mind that no referenced workgroups will be freed
- * only after a RCU grace period, so rcu_read_lock() could
- * prevent a workgroup from being freed.
- */
-static void z_erofs_rcu_callback(struct rcu_head *head)
-{
- struct z_erofs_vle_work *work = container_of(head,
- struct z_erofs_vle_work, rcu);
- struct z_erofs_vle_workgroup *grp =
- z_erofs_vle_work_workgroup(work, true);
-
- kmem_cache_free(z_erofs_workgroup_cachep, grp);
-}
-
-void erofs_workgroup_free_rcu(struct erofs_workgroup *grp)
-{
- struct z_erofs_vle_workgroup *const vgrp = container_of(grp,
- struct z_erofs_vle_workgroup, obj);
- struct z_erofs_vle_work *const work = &vgrp->work;
-
- call_rcu(&work->rcu, z_erofs_rcu_callback);
-}
-
-static void
-__z_erofs_vle_work_release(struct z_erofs_vle_workgroup *grp,
- struct z_erofs_vle_work *work __maybe_unused)
-{
- erofs_workgroup_put(&grp->obj);
-}
-
-static void z_erofs_vle_work_release(struct z_erofs_vle_work *work)
-{
- struct z_erofs_vle_workgroup *grp =
- z_erofs_vle_work_workgroup(work, true);
-
- __z_erofs_vle_work_release(grp, work);
-}
-
-static inline bool
-z_erofs_vle_work_iter_end(struct z_erofs_vle_work_builder *builder)
-{
- struct z_erofs_vle_work *work = builder->work;
-
- if (!work)
- return false;
-
- z_erofs_pagevec_ctor_exit(&builder->vector, false);
- mutex_unlock(&work->lock);
-
- /*
- * if all pending pages are added, don't hold work reference
- * any longer if the current work isn't hosted by ourselves.
- */
- if (!builder->hosted)
- __z_erofs_vle_work_release(builder->grp, work);
-
- builder->work = NULL;
- builder->grp = NULL;
- return true;
-}
-
-static inline struct page *__stagingpage_alloc(struct list_head *pagepool,
- gfp_t gfp)
-{
- struct page *page = erofs_allocpage(pagepool, gfp);
-
- if (unlikely(!page))
- return NULL;
-
- page->mapping = Z_EROFS_MAPPING_STAGING;
- return page;
-}
-
-struct z_erofs_vle_frontend {
- struct inode *const inode;
-
- struct z_erofs_vle_work_builder builder;
- struct erofs_map_blocks map;
-
- z_erofs_vle_owned_workgrp_t owned_head;
-
- /* used for applying cache strategy on the fly */
- bool backmost;
- erofs_off_t headoffset;
-};
-
-#define VLE_FRONTEND_INIT(__i) { \
- .inode = __i, \
- .map = { \
- .m_llen = 0, \
- .m_plen = 0, \
- .mpage = NULL \
- }, \
- .builder = VLE_WORK_BUILDER_INIT(), \
- .owned_head = Z_EROFS_VLE_WORKGRP_TAIL, \
- .backmost = true, }
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
-static inline bool
-should_alloc_managed_pages(struct z_erofs_vle_frontend *fe, erofs_off_t la)
-{
- if (fe->backmost)
- return true;
-
- if (EROFS_FS_ZIP_CACHE_LVL >= 2)
- return la < fe->headoffset;
-
- return false;
-}
-#else
-static inline bool
-should_alloc_managed_pages(struct z_erofs_vle_frontend *fe, erofs_off_t la)
-{
- return false;
-}
-#endif
-
-static int z_erofs_do_read_page(struct z_erofs_vle_frontend *fe,
- struct page *page,
- struct list_head *page_pool)
-{
- struct super_block *const sb = fe->inode->i_sb;
- struct erofs_sb_info *const sbi __maybe_unused = EROFS_SB(sb);
- struct erofs_map_blocks *const map = &fe->map;
- struct z_erofs_vle_work_builder *const builder = &fe->builder;
- const loff_t offset = page_offset(page);
-
- bool tight = builder_is_hooked(builder);
- struct z_erofs_vle_work *work = builder->work;
-
- enum z_erofs_cache_alloctype cache_strategy;
- enum z_erofs_page_type page_type;
- unsigned int cur, end, spiltted, index;
- int err = 0;
-
- /* register locked file pages as online pages in pack */
- z_erofs_onlinepage_init(page);
-
- spiltted = 0;
- end = PAGE_SIZE;
-repeat:
- cur = end - 1;
-
- /* lucky, within the range of the current map_blocks */
- if (offset + cur >= map->m_la &&
- offset + cur < map->m_la + map->m_llen) {
- /* didn't get a valid unzip work previously (very rare) */
- if (!builder->work)
- goto restart_now;
- goto hitted;
- }
-
- /* go ahead the next map_blocks */
- debugln("%s: [out-of-range] pos %llu", __func__, offset + cur);
-
- if (z_erofs_vle_work_iter_end(builder))
- fe->backmost = false;
-
- map->m_la = offset + cur;
- map->m_llen = 0;
- err = z_erofs_map_blocks_iter(fe->inode, map, 0);
- if (unlikely(err))
- goto err_out;
-
-restart_now:
- if (unlikely(!(map->m_flags & EROFS_MAP_MAPPED)))
- goto hitted;
-
- DBG_BUGON(map->m_plen != 1 << sbi->clusterbits);
- DBG_BUGON(erofs_blkoff(map->m_pa));
-
- err = z_erofs_vle_work_iter_begin(builder, sb, map, &fe->owned_head);
- if (unlikely(err))
- goto err_out;
-
- /* preload all compressed pages (maybe downgrade role if necessary) */
- if (should_alloc_managed_pages(fe, map->m_la))
- cache_strategy = DELAYEDALLOC;
- else
- cache_strategy = DONTALLOC;
-
- preload_compressed_pages(builder, MNGD_MAPPING(sbi),
- map->m_pa / PAGE_SIZE,
- map->m_plen / PAGE_SIZE,
- cache_strategy, page_pool, GFP_KERNEL);
-
- tight &= builder_is_hooked(builder);
- work = builder->work;
-hitted:
- cur = end - min_t(unsigned int, offset + end - map->m_la, end);
- if (unlikely(!(map->m_flags & EROFS_MAP_MAPPED))) {
- zero_user_segment(page, cur, end);
- goto next_part;
- }
-
- /* let's derive page type */
- page_type = cur ? Z_EROFS_VLE_PAGE_TYPE_HEAD :
- (!spiltted ? Z_EROFS_PAGE_TYPE_EXCLUSIVE :
- (tight ? Z_EROFS_PAGE_TYPE_EXCLUSIVE :
- Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED));
-
- if (cur)
- tight &= builder_is_followed(builder);
-
-retry:
- err = z_erofs_vle_work_add_page(builder, page, page_type);
- /* should allocate an additional staging page for pagevec */
- if (err == -EAGAIN) {
- struct page *const newpage =
- __stagingpage_alloc(page_pool, GFP_NOFS);
-
- err = z_erofs_vle_work_add_page(builder, newpage,
- Z_EROFS_PAGE_TYPE_EXCLUSIVE);
- if (likely(!err))
- goto retry;
- }
-
- if (unlikely(err))
- goto err_out;
-
- index = page->index - map->m_la / PAGE_SIZE;
-
- /* FIXME! avoid the last relundant fixup & endio */
- z_erofs_onlinepage_fixup(page, index, true);
-
- /* bump up the number of spiltted parts of a page */
- ++spiltted;
- /* also update nr_pages */
- work->nr_pages = max_t(pgoff_t, work->nr_pages, index + 1);
-next_part:
- /* can be used for verification */
- map->m_llen = offset + cur - map->m_la;
-
- end = cur;
- if (end > 0)
- goto repeat;
-
-out:
- /* FIXME! avoid the last relundant fixup & endio */
- z_erofs_onlinepage_endio(page);
-
- debugln("%s, finish page: %pK spiltted: %u map->m_llen %llu",
- __func__, page, spiltted, map->m_llen);
- return err;
-
- /* if some error occurred while processing this page */
-err_out:
- SetPageError(page);
- goto out;
-}
-
-static void z_erofs_vle_unzip_kickoff(void *ptr, int bios)
-{
- tagptr1_t t = tagptr_init(tagptr1_t, ptr);
- struct z_erofs_vle_unzip_io *io = tagptr_unfold_ptr(t);
- bool background = tagptr_unfold_tags(t);
-
- if (!background) {
- unsigned long flags;
-
- spin_lock_irqsave(&io->u.wait.lock, flags);
- if (!atomic_add_return(bios, &io->pending_bios))
- wake_up_locked(&io->u.wait);
- spin_unlock_irqrestore(&io->u.wait.lock, flags);
- return;
- }
-
- if (!atomic_add_return(bios, &io->pending_bios))
- queue_work(z_erofs_workqueue, &io->u.work);
-}
-
-static inline void z_erofs_vle_read_endio(struct bio *bio)
-{
- struct erofs_sb_info *sbi = NULL;
- blk_status_t err = bio->bi_status;
- struct bio_vec *bvec;
- struct bvec_iter_all iter_all;
-
- bio_for_each_segment_all(bvec, bio, iter_all) {
- struct page *page = bvec->bv_page;
- bool cachemngd = false;
-
- DBG_BUGON(PageUptodate(page));
- DBG_BUGON(!page->mapping);
-
- if (unlikely(!sbi && !z_erofs_page_is_staging(page))) {
- sbi = EROFS_SB(page->mapping->host->i_sb);
-
- if (time_to_inject(sbi, FAULT_READ_IO)) {
- erofs_show_injection_info(FAULT_READ_IO);
- err = BLK_STS_IOERR;
- }
- }
-
- /* sbi should already be gotten if the page is managed */
- if (sbi)
- cachemngd = erofs_page_is_managed(sbi, page);
-
- if (unlikely(err))
- SetPageError(page);
- else if (cachemngd)
- SetPageUptodate(page);
-
- if (cachemngd)
- unlock_page(page);
- }
-
- z_erofs_vle_unzip_kickoff(bio->bi_private, -1);
- bio_put(bio);
-}
-
-static struct page *z_pagemap_global[Z_EROFS_VLE_VMAP_GLOBAL_PAGES];
-static DEFINE_MUTEX(z_pagemap_global_lock);
-
-static int z_erofs_vle_unzip(struct super_block *sb,
- struct z_erofs_vle_workgroup *grp,
- struct list_head *page_pool)
-{
- struct erofs_sb_info *const sbi = EROFS_SB(sb);
- const unsigned int clusterpages = erofs_clusterpages(sbi);
-
- struct z_erofs_pagevec_ctor ctor;
- unsigned int nr_pages;
- unsigned int sparsemem_pages = 0;
- struct page *pages_onstack[Z_EROFS_VLE_VMAP_ONSTACK_PAGES];
- struct page **pages, **compressed_pages, *page;
- unsigned int algorithm;
- unsigned int i, outputsize;
-
- enum z_erofs_page_type page_type;
- bool overlapped, partial;
- struct z_erofs_vle_work *work;
- int err;
-
- might_sleep();
- work = z_erofs_vle_grab_primary_work(grp);
- DBG_BUGON(!READ_ONCE(work->nr_pages));
-
- mutex_lock(&work->lock);
- nr_pages = work->nr_pages;
-
- if (likely(nr_pages <= Z_EROFS_VLE_VMAP_ONSTACK_PAGES))
- pages = pages_onstack;
- else if (nr_pages <= Z_EROFS_VLE_VMAP_GLOBAL_PAGES &&
- mutex_trylock(&z_pagemap_global_lock))
- pages = z_pagemap_global;
- else {
-repeat:
- pages = kvmalloc_array(nr_pages, sizeof(struct page *),
- GFP_KERNEL);
-
- /* fallback to global pagemap for the lowmem scenario */
- if (unlikely(!pages)) {
- if (nr_pages > Z_EROFS_VLE_VMAP_GLOBAL_PAGES)
- goto repeat;
- else {
- mutex_lock(&z_pagemap_global_lock);
- pages = z_pagemap_global;
- }
- }
- }
-
- for (i = 0; i < nr_pages; ++i)
- pages[i] = NULL;
-
- z_erofs_pagevec_ctor_init(&ctor, Z_EROFS_NR_INLINE_PAGEVECS,
- work->pagevec, 0);
-
- for (i = 0; i < work->vcnt; ++i) {
- unsigned int pagenr;
-
- page = z_erofs_pagevec_ctor_dequeue(&ctor, &page_type);
-
- /* all pages in pagevec ought to be valid */
- DBG_BUGON(!page);
- DBG_BUGON(!page->mapping);
-
- if (z_erofs_put_stagingpage(page_pool, page))
- continue;
-
- if (page_type == Z_EROFS_VLE_PAGE_TYPE_HEAD)
- pagenr = 0;
- else
- pagenr = z_erofs_onlinepage_index(page);
-
- DBG_BUGON(pagenr >= nr_pages);
- DBG_BUGON(pages[pagenr]);
-
- pages[pagenr] = page;
- }
- sparsemem_pages = i;
-
- z_erofs_pagevec_ctor_exit(&ctor, true);
-
- overlapped = false;
- compressed_pages = grp->compressed_pages;
-
- err = 0;
- for (i = 0; i < clusterpages; ++i) {
- unsigned int pagenr;
-
- page = compressed_pages[i];
-
- /* all compressed pages ought to be valid */
- DBG_BUGON(!page);
- DBG_BUGON(!page->mapping);
-
- if (!z_erofs_page_is_staging(page)) {
- if (erofs_page_is_managed(sbi, page)) {
- if (unlikely(!PageUptodate(page)))
- err = -EIO;
- continue;
- }
-
- /*
- * only if non-head page can be selected
- * for inplace decompression
- */
- pagenr = z_erofs_onlinepage_index(page);
-
- DBG_BUGON(pagenr >= nr_pages);
- DBG_BUGON(pages[pagenr]);
- ++sparsemem_pages;
- pages[pagenr] = page;
-
- overlapped = true;
- }
-
- /* PG_error needs checking for inplaced and staging pages */
- if (unlikely(PageError(page))) {
- DBG_BUGON(PageUptodate(page));
- err = -EIO;
- }
- }
-
- if (unlikely(err))
- goto out;
-
- if (nr_pages << PAGE_SHIFT >= work->pageofs + grp->llen) {
- outputsize = grp->llen;
- partial = !(grp->flags & Z_EROFS_VLE_WORKGRP_FULL_LENGTH);
- } else {
- outputsize = (nr_pages << PAGE_SHIFT) - work->pageofs;
- partial = true;
- }
-
- if (z_erofs_vle_workgrp_fmt(grp) == Z_EROFS_VLE_WORKGRP_FMT_PLAIN)
- algorithm = Z_EROFS_COMPRESSION_SHIFTED;
- else
- algorithm = Z_EROFS_COMPRESSION_LZ4;
-
- err = z_erofs_decompress(&(struct z_erofs_decompress_req) {
- .sb = sb,
- .in = compressed_pages,
- .out = pages,
- .pageofs_out = work->pageofs,
- .inputsize = PAGE_SIZE,
- .outputsize = outputsize,
- .alg = algorithm,
- .inplace_io = overlapped,
- .partial_decoding = partial
- }, page_pool);
-
-out:
- /* must handle all compressed pages before endding pages */
- for (i = 0; i < clusterpages; ++i) {
- page = compressed_pages[i];
-
- if (erofs_page_is_managed(sbi, page))
- continue;
-
- /* recycle all individual staging pages */
- (void)z_erofs_put_stagingpage(page_pool, page);
-
- WRITE_ONCE(compressed_pages[i], NULL);
- }
-
- for (i = 0; i < nr_pages; ++i) {
- page = pages[i];
- if (!page)
- continue;
-
- DBG_BUGON(!page->mapping);
-
- /* recycle all individual staging pages */
- if (z_erofs_put_stagingpage(page_pool, page))
- continue;
-
- if (unlikely(err < 0))
- SetPageError(page);
-
- z_erofs_onlinepage_endio(page);
- }
-
- if (pages == z_pagemap_global)
- mutex_unlock(&z_pagemap_global_lock);
- else if (unlikely(pages != pages_onstack))
- kvfree(pages);
-
- work->nr_pages = 0;
- work->vcnt = 0;
-
- /* all work locks MUST be taken before the following line */
-
- WRITE_ONCE(grp->next, Z_EROFS_VLE_WORKGRP_NIL);
-
- /* all work locks SHOULD be released right now */
- mutex_unlock(&work->lock);
-
- z_erofs_vle_work_release(work);
- return err;
-}
-
-static void z_erofs_vle_unzip_all(struct super_block *sb,
- struct z_erofs_vle_unzip_io *io,
- struct list_head *page_pool)
-{
- z_erofs_vle_owned_workgrp_t owned = io->head;
-
- while (owned != Z_EROFS_VLE_WORKGRP_TAIL_CLOSED) {
- struct z_erofs_vle_workgroup *grp;
-
- /* no possible that 'owned' equals Z_EROFS_WORK_TPTR_TAIL */
- DBG_BUGON(owned == Z_EROFS_VLE_WORKGRP_TAIL);
-
- /* no possible that 'owned' equals NULL */
- DBG_BUGON(owned == Z_EROFS_VLE_WORKGRP_NIL);
-
- grp = container_of(owned, struct z_erofs_vle_workgroup, next);
- owned = READ_ONCE(grp->next);
-
- z_erofs_vle_unzip(sb, grp, page_pool);
- }
-}
-
-static void z_erofs_vle_unzip_wq(struct work_struct *work)
-{
- struct z_erofs_vle_unzip_io_sb *iosb = container_of(work,
- struct z_erofs_vle_unzip_io_sb, io.u.work);
- LIST_HEAD(page_pool);
-
- DBG_BUGON(iosb->io.head == Z_EROFS_VLE_WORKGRP_TAIL_CLOSED);
- z_erofs_vle_unzip_all(iosb->sb, &iosb->io, &page_pool);
-
- put_pages_list(&page_pool);
- kvfree(iosb);
-}
-
-static struct page *
-pickup_page_for_submission(struct z_erofs_vle_workgroup *grp,
- unsigned int nr,
- struct list_head *pagepool,
- struct address_space *mc,
- gfp_t gfp)
-{
- /* determined at compile time to avoid too many #ifdefs */
- const bool nocache = __builtin_constant_p(mc) ? !mc : false;
- const pgoff_t index = grp->obj.index;
- bool tocache = false;
-
- struct address_space *mapping;
- struct page *oldpage, *page;
-
- compressed_page_t t;
- int justfound;
-
-repeat:
- page = READ_ONCE(grp->compressed_pages[nr]);
- oldpage = page;
-
- if (!page)
- goto out_allocpage;
-
- /*
- * the cached page has not been allocated and
- * an placeholder is out there, prepare it now.
- */
- if (!nocache && page == PAGE_UNALLOCATED) {
- tocache = true;
- goto out_allocpage;
- }
-
- /* process the target tagged pointer */
- t = tagptr_init(compressed_page_t, page);
- justfound = tagptr_unfold_tags(t);
- page = tagptr_unfold_ptr(t);
-
- mapping = READ_ONCE(page->mapping);
-
- /*
- * if managed cache is disabled, it's no way to
- * get such a cached-like page.
- */
- if (nocache) {
- /* if managed cache is disabled, it is impossible `justfound' */
- DBG_BUGON(justfound);
-
- /* and it should be locked, not uptodate, and not truncated */
- DBG_BUGON(!PageLocked(page));
- DBG_BUGON(PageUptodate(page));
- DBG_BUGON(!mapping);
- goto out;
- }
-
- /*
- * unmanaged (file) pages are all locked solidly,
- * therefore it is impossible for `mapping' to be NULL.
- */
- if (mapping && mapping != mc)
- /* ought to be unmanaged pages */
- goto out;
-
- lock_page(page);
-
- /* only true if page reclaim goes wrong, should never happen */
- DBG_BUGON(justfound && PagePrivate(page));
-
- /* the page is still in manage cache */
- if (page->mapping == mc) {
- WRITE_ONCE(grp->compressed_pages[nr], page);
-
- ClearPageError(page);
- if (!PagePrivate(page)) {
- /*
- * impossible to be !PagePrivate(page) for
- * the current restriction as well if
- * the page is already in compressed_pages[].
- */
- DBG_BUGON(!justfound);
-
- justfound = 0;
- set_page_private(page, (unsigned long)grp);
- SetPagePrivate(page);
- }
-
- /* no need to submit io if it is already up-to-date */
- if (PageUptodate(page)) {
- unlock_page(page);
- page = NULL;
- }
- goto out;
- }
-
- /*
- * the managed page has been truncated, it's unsafe to
- * reuse this one, let's allocate a new cache-managed page.
- */
- DBG_BUGON(page->mapping);
- DBG_BUGON(!justfound);
-
- tocache = true;
- unlock_page(page);
- put_page(page);
-out_allocpage:
- page = __stagingpage_alloc(pagepool, gfp);
- if (oldpage != cmpxchg(&grp->compressed_pages[nr], oldpage, page)) {
- list_add(&page->lru, pagepool);
- cpu_relax();
- goto repeat;
- }
- if (nocache || !tocache)
- goto out;
- if (add_to_page_cache_lru(page, mc, index + nr, gfp)) {
- page->mapping = Z_EROFS_MAPPING_STAGING;
- goto out;
- }
-
- set_page_private(page, (unsigned long)grp);
- SetPagePrivate(page);
-out: /* the only exit (for tracing and debugging) */
- return page;
-}
-
-static struct z_erofs_vle_unzip_io *
-jobqueue_init(struct super_block *sb,
- struct z_erofs_vle_unzip_io *io,
- bool foreground)
-{
- struct z_erofs_vle_unzip_io_sb *iosb;
-
- if (foreground) {
- /* waitqueue available for foreground io */
- DBG_BUGON(!io);
-
- init_waitqueue_head(&io->u.wait);
- atomic_set(&io->pending_bios, 0);
- goto out;
- }
-
- iosb = kvzalloc(sizeof(*iosb), GFP_KERNEL | __GFP_NOFAIL);
- DBG_BUGON(!iosb);
-
- /* initialize fields in the allocated descriptor */
- io = &iosb->io;
- iosb->sb = sb;
- INIT_WORK(&io->u.work, z_erofs_vle_unzip_wq);
-out:
- io->head = Z_EROFS_VLE_WORKGRP_TAIL_CLOSED;
- return io;
-}
-
-/* define workgroup jobqueue types */
-enum {
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
- JQ_BYPASS,
-#endif
- JQ_SUBMIT,
- NR_JOBQUEUES,
-};
-
-static void *jobqueueset_init(struct super_block *sb,
- z_erofs_vle_owned_workgrp_t qtail[],
- struct z_erofs_vle_unzip_io *q[],
- struct z_erofs_vle_unzip_io *fgq,
- bool forcefg)
-{
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
- /*
- * if managed cache is enabled, bypass jobqueue is needed,
- * no need to read from device for all workgroups in this queue.
- */
- q[JQ_BYPASS] = jobqueue_init(sb, fgq + JQ_BYPASS, true);
- qtail[JQ_BYPASS] = &q[JQ_BYPASS]->head;
-#endif
-
- q[JQ_SUBMIT] = jobqueue_init(sb, fgq + JQ_SUBMIT, forcefg);
- qtail[JQ_SUBMIT] = &q[JQ_SUBMIT]->head;
-
- return tagptr_cast_ptr(tagptr_fold(tagptr1_t, q[JQ_SUBMIT], !forcefg));
-}
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
-static void move_to_bypass_jobqueue(struct z_erofs_vle_workgroup *grp,
- z_erofs_vle_owned_workgrp_t qtail[],
- z_erofs_vle_owned_workgrp_t owned_head)
-{
- z_erofs_vle_owned_workgrp_t *const submit_qtail = qtail[JQ_SUBMIT];
- z_erofs_vle_owned_workgrp_t *const bypass_qtail = qtail[JQ_BYPASS];
-
- DBG_BUGON(owned_head == Z_EROFS_VLE_WORKGRP_TAIL_CLOSED);
- if (owned_head == Z_EROFS_VLE_WORKGRP_TAIL)
- owned_head = Z_EROFS_VLE_WORKGRP_TAIL_CLOSED;
-
- WRITE_ONCE(grp->next, Z_EROFS_VLE_WORKGRP_TAIL_CLOSED);
-
- WRITE_ONCE(*submit_qtail, owned_head);
- WRITE_ONCE(*bypass_qtail, &grp->next);
-
- qtail[JQ_BYPASS] = &grp->next;
-}
-
-static bool postsubmit_is_all_bypassed(struct z_erofs_vle_unzip_io *q[],
- unsigned int nr_bios,
- bool force_fg)
-{
- /*
- * although background is preferred, no one is pending for submission.
- * don't issue workqueue for decompression but drop it directly instead.
- */
- if (force_fg || nr_bios)
- return false;
-
- kvfree(container_of(q[JQ_SUBMIT],
- struct z_erofs_vle_unzip_io_sb,
- io));
- return true;
-}
-#else
-static void move_to_bypass_jobqueue(struct z_erofs_vle_workgroup *grp,
- z_erofs_vle_owned_workgrp_t qtail[],
- z_erofs_vle_owned_workgrp_t owned_head)
-{
- /* impossible to bypass submission for managed cache disabled */
- DBG_BUGON(1);
-}
-
-static bool postsubmit_is_all_bypassed(struct z_erofs_vle_unzip_io *q[],
- unsigned int nr_bios,
- bool force_fg)
-{
- /* bios should be >0 if managed cache is disabled */
- DBG_BUGON(!nr_bios);
- return false;
-}
-#endif
-
-static bool z_erofs_vle_submit_all(struct super_block *sb,
- z_erofs_vle_owned_workgrp_t owned_head,
- struct list_head *pagepool,
- struct z_erofs_vle_unzip_io *fgq,
- bool force_fg)
-{
- struct erofs_sb_info *const sbi = EROFS_SB(sb);
- const unsigned int clusterpages = erofs_clusterpages(sbi);
- const gfp_t gfp = GFP_NOFS;
-
- z_erofs_vle_owned_workgrp_t qtail[NR_JOBQUEUES];
- struct z_erofs_vle_unzip_io *q[NR_JOBQUEUES];
- struct bio *bio;
- void *bi_private;
- /* since bio will be NULL, no need to initialize last_index */
- pgoff_t uninitialized_var(last_index);
- bool force_submit = false;
- unsigned int nr_bios;
-
- if (unlikely(owned_head == Z_EROFS_VLE_WORKGRP_TAIL))
- return false;
-
- force_submit = false;
- bio = NULL;
- nr_bios = 0;
- bi_private = jobqueueset_init(sb, qtail, q, fgq, force_fg);
-
- /* by default, all need io submission */
- q[JQ_SUBMIT]->head = owned_head;
-
- do {
- struct z_erofs_vle_workgroup *grp;
- pgoff_t first_index;
- struct page *page;
- unsigned int i = 0, bypass = 0;
- int err;
-
- /* no possible 'owned_head' equals the following */
- DBG_BUGON(owned_head == Z_EROFS_VLE_WORKGRP_TAIL_CLOSED);
- DBG_BUGON(owned_head == Z_EROFS_VLE_WORKGRP_NIL);
-
- grp = container_of(owned_head,
- struct z_erofs_vle_workgroup, next);
-
- /* close the main owned chain at first */
- owned_head = cmpxchg(&grp->next, Z_EROFS_VLE_WORKGRP_TAIL,
- Z_EROFS_VLE_WORKGRP_TAIL_CLOSED);
-
- first_index = grp->obj.index;
- force_submit |= (first_index != last_index + 1);
-
-repeat:
- page = pickup_page_for_submission(grp, i, pagepool,
- MNGD_MAPPING(sbi), gfp);
- if (!page) {
- force_submit = true;
- ++bypass;
- goto skippage;
- }
-
- if (bio && force_submit) {
-submit_bio_retry:
- __submit_bio(bio, REQ_OP_READ, 0);
- bio = NULL;
- }
-
- if (!bio) {
- bio = erofs_grab_bio(sb, first_index + i,
- BIO_MAX_PAGES, bi_private,
- z_erofs_vle_read_endio, true);
- ++nr_bios;
- }
-
- err = bio_add_page(bio, page, PAGE_SIZE, 0);
- if (err < PAGE_SIZE)
- goto submit_bio_retry;
-
- force_submit = false;
- last_index = first_index + i;
-skippage:
- if (++i < clusterpages)
- goto repeat;
-
- if (bypass < clusterpages)
- qtail[JQ_SUBMIT] = &grp->next;
- else
- move_to_bypass_jobqueue(grp, qtail, owned_head);
- } while (owned_head != Z_EROFS_VLE_WORKGRP_TAIL);
-
- if (bio)
- __submit_bio(bio, REQ_OP_READ, 0);
-
- if (postsubmit_is_all_bypassed(q, nr_bios, force_fg))
- return true;
-
- z_erofs_vle_unzip_kickoff(bi_private, nr_bios);
- return true;
-}
-
-static void z_erofs_submit_and_unzip(struct z_erofs_vle_frontend *f,
- struct list_head *pagepool,
- bool force_fg)
-{
- struct super_block *sb = f->inode->i_sb;
- struct z_erofs_vle_unzip_io io[NR_JOBQUEUES];
-
- if (!z_erofs_vle_submit_all(sb, f->owned_head, pagepool, io, force_fg))
- return;
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
- z_erofs_vle_unzip_all(sb, &io[JQ_BYPASS], pagepool);
-#endif
- if (!force_fg)
- return;
-
- /* wait until all bios are completed */
- wait_event(io[JQ_SUBMIT].u.wait,
- !atomic_read(&io[JQ_SUBMIT].pending_bios));
-
- /* let's synchronous decompression */
- z_erofs_vle_unzip_all(sb, &io[JQ_SUBMIT], pagepool);
-}
-
-static int z_erofs_vle_normalaccess_readpage(struct file *file,
- struct page *page)
-{
- struct inode *const inode = page->mapping->host;
- struct z_erofs_vle_frontend f = VLE_FRONTEND_INIT(inode);
- int err;
- LIST_HEAD(pagepool);
-
- trace_erofs_readpage(page, false);
-
- f.headoffset = (erofs_off_t)page->index << PAGE_SHIFT;
-
- err = z_erofs_do_read_page(&f, page, &pagepool);
- (void)z_erofs_vle_work_iter_end(&f.builder);
-
- if (err) {
- errln("%s, failed to read, err [%d]", __func__, err);
- goto out;
- }
-
- z_erofs_submit_and_unzip(&f, &pagepool, true);
-out:
- if (f.map.mpage)
- put_page(f.map.mpage);
-
- /* clean up the remaining free pages */
- put_pages_list(&pagepool);
- return 0;
-}
-
-static int z_erofs_vle_normalaccess_readpages(struct file *filp,
- struct address_space *mapping,
- struct list_head *pages,
- unsigned int nr_pages)
-{
- struct inode *const inode = mapping->host;
- struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
-
- bool sync = __should_decompress_synchronously(sbi, nr_pages);
- struct z_erofs_vle_frontend f = VLE_FRONTEND_INIT(inode);
- gfp_t gfp = mapping_gfp_constraint(mapping, GFP_KERNEL);
- struct page *head = NULL;
- LIST_HEAD(pagepool);
-
- trace_erofs_readpages(mapping->host, lru_to_page(pages),
- nr_pages, false);
-
- f.headoffset = (erofs_off_t)lru_to_page(pages)->index << PAGE_SHIFT;
-
- for (; nr_pages; --nr_pages) {
- struct page *page = lru_to_page(pages);
-
- prefetchw(&page->flags);
- list_del(&page->lru);
-
- /*
- * A pure asynchronous readahead is indicated if
- * a PG_readahead marked page is hitted at first.
- * Let's also do asynchronous decompression for this case.
- */
- sync &= !(PageReadahead(page) && !head);
-
- if (add_to_page_cache_lru(page, mapping, page->index, gfp)) {
- list_add(&page->lru, &pagepool);
- continue;
- }
-
- set_page_private(page, (unsigned long)head);
- head = page;
- }
-
- while (head) {
- struct page *page = head;
- int err;
-
- /* traversal in reverse order */
- head = (void *)page_private(page);
-
- err = z_erofs_do_read_page(&f, page, &pagepool);
- if (err) {
- struct erofs_vnode *vi = EROFS_V(inode);
-
- errln("%s, readahead error at page %lu of nid %llu",
- __func__, page->index, vi->nid);
- }
-
- put_page(page);
- }
-
- (void)z_erofs_vle_work_iter_end(&f.builder);
-
- z_erofs_submit_and_unzip(&f, &pagepool, sync);
-
- if (f.map.mpage)
- put_page(f.map.mpage);
-
- /* clean up the remaining free pages */
- put_pages_list(&pagepool);
- return 0;
-}
-
-const struct address_space_operations z_erofs_vle_normalaccess_aops = {
- .readpage = z_erofs_vle_normalaccess_readpage,
- .readpages = z_erofs_vle_normalaccess_readpages,
-};
-
diff --git a/drivers/staging/erofs/unzip_vle.h b/drivers/staging/erofs/unzip_vle.h
deleted file mode 100644
index ab509d75aefd..000000000000
--- a/drivers/staging/erofs/unzip_vle.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * linux/drivers/staging/erofs/unzip_vle.h
- *
- * Copyright (C) 2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#ifndef __EROFS_FS_UNZIP_VLE_H
-#define __EROFS_FS_UNZIP_VLE_H
-
-#include "internal.h"
-#include "unzip_pagevec.h"
-
-#define Z_EROFS_NR_INLINE_PAGEVECS 3
-
-/*
- * Structure fields follow one of the following exclusion rules.
- *
- * I: Modifiable by initialization/destruction paths and read-only
- * for everyone else.
- *
- */
-
-struct z_erofs_vle_work {
- struct mutex lock;
-
- /* I: decompression offset in page */
- unsigned short pageofs;
- unsigned short nr_pages;
-
- /* L: queued pages in pagevec[] */
- unsigned vcnt;
-
- union {
- /* L: pagevec */
- erofs_vtptr_t pagevec[Z_EROFS_NR_INLINE_PAGEVECS];
- struct rcu_head rcu;
- };
-};
-
-#define Z_EROFS_VLE_WORKGRP_FMT_PLAIN 0
-#define Z_EROFS_VLE_WORKGRP_FMT_LZ4 1
-#define Z_EROFS_VLE_WORKGRP_FMT_MASK 1
-#define Z_EROFS_VLE_WORKGRP_FULL_LENGTH 2
-
-typedef void *z_erofs_vle_owned_workgrp_t;
-
-struct z_erofs_vle_workgroup {
- struct erofs_workgroup obj;
- struct z_erofs_vle_work work;
-
- /* point to next owned_workgrp_t */
- z_erofs_vle_owned_workgrp_t next;
-
- /* compressed pages (including multi-usage pages) */
- struct page *compressed_pages[Z_EROFS_CLUSTER_MAX_PAGES];
- unsigned int llen, flags;
-};
-
-/* let's avoid the valid 32-bit kernel addresses */
-
-/* the chained workgroup has't submitted io (still open) */
-#define Z_EROFS_VLE_WORKGRP_TAIL ((void *)0x5F0ECAFE)
-/* the chained workgroup has already submitted io */
-#define Z_EROFS_VLE_WORKGRP_TAIL_CLOSED ((void *)0x5F0EDEAD)
-
-#define Z_EROFS_VLE_WORKGRP_NIL (NULL)
-
-#define z_erofs_vle_workgrp_fmt(grp) \
- ((grp)->flags & Z_EROFS_VLE_WORKGRP_FMT_MASK)
-
-static inline void z_erofs_vle_set_workgrp_fmt(
- struct z_erofs_vle_workgroup *grp,
- unsigned int fmt)
-{
- grp->flags = fmt | (grp->flags & ~Z_EROFS_VLE_WORKGRP_FMT_MASK);
-}
-
-
-/* definitions if multiref is disabled */
-#define z_erofs_vle_grab_primary_work(grp) (&(grp)->work)
-#define z_erofs_vle_grab_work(grp, pageofs) (&(grp)->work)
-#define z_erofs_vle_work_workgroup(wrk, primary) \
- ((primary) ? container_of(wrk, \
- struct z_erofs_vle_workgroup, work) : \
- ({ BUG(); (void *)NULL; }))
-
-
-#define Z_EROFS_WORKGROUP_SIZE sizeof(struct z_erofs_vle_workgroup)
-
-struct z_erofs_vle_unzip_io {
- atomic_t pending_bios;
- z_erofs_vle_owned_workgrp_t head;
-
- union {
- wait_queue_head_t wait;
- struct work_struct work;
- } u;
-};
-
-struct z_erofs_vle_unzip_io_sb {
- struct z_erofs_vle_unzip_io io;
- struct super_block *sb;
-};
-
-#define Z_EROFS_ONLINEPAGE_COUNT_BITS 2
-#define Z_EROFS_ONLINEPAGE_COUNT_MASK ((1 << Z_EROFS_ONLINEPAGE_COUNT_BITS) - 1)
-#define Z_EROFS_ONLINEPAGE_INDEX_SHIFT (Z_EROFS_ONLINEPAGE_COUNT_BITS)
-
-/*
- * waiters (aka. ongoing_packs): # to unlock the page
- * sub-index: 0 - for partial page, >= 1 full page sub-index
- */
-typedef atomic_t z_erofs_onlinepage_t;
-
-/* type punning */
-union z_erofs_onlinepage_converter {
- z_erofs_onlinepage_t *o;
- unsigned long *v;
-};
-
-static inline unsigned z_erofs_onlinepage_index(struct page *page)
-{
- union z_erofs_onlinepage_converter u;
-
- DBG_BUGON(!PagePrivate(page));
- u.v = &page_private(page);
-
- return atomic_read(u.o) >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT;
-}
-
-static inline void z_erofs_onlinepage_init(struct page *page)
-{
- union {
- z_erofs_onlinepage_t o;
- unsigned long v;
- /* keep from being unlocked in advance */
- } u = { .o = ATOMIC_INIT(1) };
-
- set_page_private(page, u.v);
- smp_wmb();
- SetPagePrivate(page);
-}
-
-static inline void z_erofs_onlinepage_fixup(struct page *page,
- uintptr_t index, bool down)
-{
- unsigned long *p, o, v, id;
-repeat:
- p = &page_private(page);
- o = READ_ONCE(*p);
-
- id = o >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT;
- if (id) {
- if (!index)
- return;
-
- DBG_BUGON(id != index);
- }
-
- v = (index << Z_EROFS_ONLINEPAGE_INDEX_SHIFT) |
- ((o & Z_EROFS_ONLINEPAGE_COUNT_MASK) + (unsigned)down);
- if (cmpxchg(p, o, v) != o)
- goto repeat;
-}
-
-static inline void z_erofs_onlinepage_endio(struct page *page)
-{
- union z_erofs_onlinepage_converter u;
- unsigned v;
-
- DBG_BUGON(!PagePrivate(page));
- u.v = &page_private(page);
-
- v = atomic_dec_return(u.o);
- if (!(v & Z_EROFS_ONLINEPAGE_COUNT_MASK)) {
- ClearPagePrivate(page);
- if (!PageError(page))
- SetPageUptodate(page);
- unlock_page(page);
- }
-
- debugln("%s, page %p value %x", __func__, page, atomic_read(u.o));
-}
-
-#define Z_EROFS_VLE_VMAP_ONSTACK_PAGES \
- min_t(unsigned int, THREAD_SIZE / 8 / sizeof(struct page *), 96U)
-#define Z_EROFS_VLE_VMAP_GLOBAL_PAGES 2048
-
-#endif
-
diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c
deleted file mode 100644
index 4bbd3bf34acd..000000000000
--- a/drivers/staging/erofs/utils.c
+++ /dev/null
@@ -1,353 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/utils.c
- *
- * Copyright (C) 2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-
-#include "internal.h"
-#include <linux/pagevec.h>
-
-struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp)
-{
- struct page *page;
-
- if (!list_empty(pool)) {
- page = lru_to_page(pool);
- list_del(&page->lru);
- } else {
- page = alloc_pages(gfp | __GFP_NOFAIL, 0);
- }
- return page;
-}
-
-#if (EROFS_PCPUBUF_NR_PAGES > 0)
-static struct {
- u8 data[PAGE_SIZE * EROFS_PCPUBUF_NR_PAGES];
-} ____cacheline_aligned_in_smp erofs_pcpubuf[NR_CPUS];
-
-void *erofs_get_pcpubuf(unsigned int pagenr)
-{
- preempt_disable();
- return &erofs_pcpubuf[smp_processor_id()].data[pagenr * PAGE_SIZE];
-}
-#endif
-
-/* global shrink count (for all mounted EROFS instances) */
-static atomic_long_t erofs_global_shrink_cnt;
-
-#ifdef CONFIG_EROFS_FS_ZIP
-#define __erofs_workgroup_get(grp) atomic_inc(&(grp)->refcount)
-#define __erofs_workgroup_put(grp) atomic_dec(&(grp)->refcount)
-
-static int erofs_workgroup_get(struct erofs_workgroup *grp)
-{
- int o;
-
-repeat:
- o = erofs_wait_on_workgroup_freezed(grp);
- if (unlikely(o <= 0))
- return -1;
-
- if (unlikely(atomic_cmpxchg(&grp->refcount, o, o + 1) != o))
- goto repeat;
-
- /* decrease refcount paired by erofs_workgroup_put */
- if (unlikely(o == 1))
- atomic_long_dec(&erofs_global_shrink_cnt);
- return 0;
-}
-
-struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
- pgoff_t index, bool *tag)
-{
- struct erofs_sb_info *sbi = EROFS_SB(sb);
- struct erofs_workgroup *grp;
-
-repeat:
- rcu_read_lock();
- grp = radix_tree_lookup(&sbi->workstn_tree, index);
- if (grp) {
- *tag = xa_pointer_tag(grp);
- grp = xa_untag_pointer(grp);
-
- if (erofs_workgroup_get(grp)) {
- /* prefer to relax rcu read side */
- rcu_read_unlock();
- goto repeat;
- }
-
- DBG_BUGON(index != grp->index);
- }
- rcu_read_unlock();
- return grp;
-}
-
-int erofs_register_workgroup(struct super_block *sb,
- struct erofs_workgroup *grp,
- bool tag)
-{
- struct erofs_sb_info *sbi;
- int err;
-
- /* grp shouldn't be broken or used before */
- if (unlikely(atomic_read(&grp->refcount) != 1)) {
- DBG_BUGON(1);
- return -EINVAL;
- }
-
- err = radix_tree_preload(GFP_NOFS);
- if (err)
- return err;
-
- sbi = EROFS_SB(sb);
- erofs_workstn_lock(sbi);
-
- grp = xa_tag_pointer(grp, tag);
-
- /*
- * Bump up reference count before making this workgroup
- * visible to other users in order to avoid potential UAF
- * without serialized by erofs_workstn_lock.
- */
- __erofs_workgroup_get(grp);
-
- err = radix_tree_insert(&sbi->workstn_tree,
- grp->index, grp);
- if (unlikely(err))
- /*
- * it's safe to decrease since the workgroup isn't visible
- * and refcount >= 2 (cannot be freezed).
- */
- __erofs_workgroup_put(grp);
-
- erofs_workstn_unlock(sbi);
- radix_tree_preload_end();
- return err;
-}
-
-static void __erofs_workgroup_free(struct erofs_workgroup *grp)
-{
- atomic_long_dec(&erofs_global_shrink_cnt);
- erofs_workgroup_free_rcu(grp);
-}
-
-int erofs_workgroup_put(struct erofs_workgroup *grp)
-{
- int count = atomic_dec_return(&grp->refcount);
-
- if (count == 1)
- atomic_long_inc(&erofs_global_shrink_cnt);
- else if (!count)
- __erofs_workgroup_free(grp);
- return count;
-}
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
-/* for cache-managed case, customized reclaim paths exist */
-static void erofs_workgroup_unfreeze_final(struct erofs_workgroup *grp)
-{
- erofs_workgroup_unfreeze(grp, 0);
- __erofs_workgroup_free(grp);
-}
-
-static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
- struct erofs_workgroup *grp,
- bool cleanup)
-{
- /*
- * for managed cache enabled, the refcount of workgroups
- * themselves could be < 0 (freezed). So there is no guarantee
- * that all refcount > 0 if managed cache is enabled.
- */
- if (!erofs_workgroup_try_to_freeze(grp, 1))
- return false;
-
- /*
- * note that all cached pages should be unlinked
- * before delete it from the radix tree.
- * Otherwise some cached pages of an orphan old workgroup
- * could be still linked after the new one is available.
- */
- if (erofs_try_to_free_all_cached_pages(sbi, grp)) {
- erofs_workgroup_unfreeze(grp, 1);
- return false;
- }
-
- /*
- * it is impossible to fail after the workgroup is freezed,
- * however in order to avoid some race conditions, add a
- * DBG_BUGON to observe this in advance.
- */
- DBG_BUGON(xa_untag_pointer(radix_tree_delete(&sbi->workstn_tree,
- grp->index)) != grp);
-
- /*
- * if managed cache is enable, the last refcount
- * should indicate the related workstation.
- */
- erofs_workgroup_unfreeze_final(grp);
- return true;
-}
-
-#else
-/* for nocache case, no customized reclaim path at all */
-static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
- struct erofs_workgroup *grp,
- bool cleanup)
-{
- int cnt = atomic_read(&grp->refcount);
-
- DBG_BUGON(cnt <= 0);
- DBG_BUGON(cleanup && cnt != 1);
-
- if (cnt > 1)
- return false;
-
- DBG_BUGON(xa_untag_pointer(radix_tree_delete(&sbi->workstn_tree,
- grp->index)) != grp);
-
- /* (rarely) could be grabbed again when freeing */
- erofs_workgroup_put(grp);
- return true;
-}
-
-#endif
-
-unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
- unsigned long nr_shrink,
- bool cleanup)
-{
- pgoff_t first_index = 0;
- void *batch[PAGEVEC_SIZE];
- unsigned int freed = 0;
-
- int i, found;
-repeat:
- erofs_workstn_lock(sbi);
-
- found = radix_tree_gang_lookup(&sbi->workstn_tree,
- batch, first_index, PAGEVEC_SIZE);
-
- for (i = 0; i < found; ++i) {
- struct erofs_workgroup *grp = xa_untag_pointer(batch[i]);
-
- first_index = grp->index + 1;
-
- /* try to shrink each valid workgroup */
- if (!erofs_try_to_release_workgroup(sbi, grp, cleanup))
- continue;
-
- ++freed;
- if (unlikely(!--nr_shrink))
- break;
- }
- erofs_workstn_unlock(sbi);
-
- if (i && nr_shrink)
- goto repeat;
- return freed;
-}
-
-#endif
-
-/* protected by 'erofs_sb_list_lock' */
-static unsigned int shrinker_run_no;
-
-/* protects the mounted 'erofs_sb_list' */
-static DEFINE_SPINLOCK(erofs_sb_list_lock);
-static LIST_HEAD(erofs_sb_list);
-
-void erofs_register_super(struct super_block *sb)
-{
- struct erofs_sb_info *sbi = EROFS_SB(sb);
-
- mutex_init(&sbi->umount_mutex);
-
- spin_lock(&erofs_sb_list_lock);
- list_add(&sbi->list, &erofs_sb_list);
- spin_unlock(&erofs_sb_list_lock);
-}
-
-void erofs_unregister_super(struct super_block *sb)
-{
- spin_lock(&erofs_sb_list_lock);
- list_del(&EROFS_SB(sb)->list);
- spin_unlock(&erofs_sb_list_lock);
-}
-
-static unsigned long erofs_shrink_count(struct shrinker *shrink,
- struct shrink_control *sc)
-{
- return atomic_long_read(&erofs_global_shrink_cnt);
-}
-
-static unsigned long erofs_shrink_scan(struct shrinker *shrink,
- struct shrink_control *sc)
-{
- struct erofs_sb_info *sbi;
- struct list_head *p;
-
- unsigned long nr = sc->nr_to_scan;
- unsigned int run_no;
- unsigned long freed = 0;
-
- spin_lock(&erofs_sb_list_lock);
- do
- run_no = ++shrinker_run_no;
- while (run_no == 0);
-
- /* Iterate over all mounted superblocks and try to shrink them */
- p = erofs_sb_list.next;
- while (p != &erofs_sb_list) {
- sbi = list_entry(p, struct erofs_sb_info, list);
-
- /*
- * We move the ones we do to the end of the list, so we stop
- * when we see one we have already done.
- */
- if (sbi->shrinker_run_no == run_no)
- break;
-
- if (!mutex_trylock(&sbi->umount_mutex)) {
- p = p->next;
- continue;
- }
-
- spin_unlock(&erofs_sb_list_lock);
- sbi->shrinker_run_no = run_no;
-
-#ifdef CONFIG_EROFS_FS_ZIP
- freed += erofs_shrink_workstation(sbi, nr, false);
-#endif
-
- spin_lock(&erofs_sb_list_lock);
- /* Get the next list element before we move this one */
- p = p->next;
-
- /*
- * Move this one to the end of the list to provide some
- * fairness.
- */
- list_move_tail(&sbi->list, &erofs_sb_list);
- mutex_unlock(&sbi->umount_mutex);
-
- if (freed >= nr)
- break;
- }
- spin_unlock(&erofs_sb_list_lock);
- return freed;
-}
-
-struct shrinker erofs_shrinker_info = {
- .scan_objects = erofs_shrink_scan,
- .count_objects = erofs_shrink_count,
- .seeks = DEFAULT_SEEKS,
-};
-
diff --git a/drivers/staging/erofs/xattr.c b/drivers/staging/erofs/xattr.c
deleted file mode 100644
index df40654b9fbb..000000000000
--- a/drivers/staging/erofs/xattr.c
+++ /dev/null
@@ -1,704 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/xattr.c
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#include <linux/security.h>
-#include "xattr.h"
-
-struct xattr_iter {
- struct super_block *sb;
- struct page *page;
- void *kaddr;
-
- erofs_blk_t blkaddr;
- unsigned int ofs;
-};
-
-static inline void xattr_iter_end(struct xattr_iter *it, bool atomic)
-{
- /* the only user of kunmap() is 'init_inode_xattrs' */
- if (unlikely(!atomic))
- kunmap(it->page);
- else
- kunmap_atomic(it->kaddr);
-
- unlock_page(it->page);
- put_page(it->page);
-}
-
-static inline void xattr_iter_end_final(struct xattr_iter *it)
-{
- if (!it->page)
- return;
-
- xattr_iter_end(it, true);
-}
-
-static int init_inode_xattrs(struct inode *inode)
-{
- struct erofs_vnode *const vi = EROFS_V(inode);
- struct xattr_iter it;
- unsigned int i;
- struct erofs_xattr_ibody_header *ih;
- struct super_block *sb;
- struct erofs_sb_info *sbi;
- bool atomic_map;
- int ret = 0;
-
- /* the most case is that xattrs of this inode are initialized. */
- if (test_bit(EROFS_V_EA_INITED_BIT, &vi->flags))
- return 0;
-
- if (wait_on_bit_lock(&vi->flags, EROFS_V_BL_XATTR_BIT, TASK_KILLABLE))
- return -ERESTARTSYS;
-
- /* someone has initialized xattrs for us? */
- if (test_bit(EROFS_V_EA_INITED_BIT, &vi->flags))
- goto out_unlock;
-
- /*
- * bypass all xattr operations if ->xattr_isize is not greater than
- * sizeof(struct erofs_xattr_ibody_header), in detail:
- * 1) it is not enough to contain erofs_xattr_ibody_header then
- * ->xattr_isize should be 0 (it means no xattr);
- * 2) it is just to contain erofs_xattr_ibody_header, which is on-disk
- * undefined right now (maybe use later with some new sb feature).
- */
- if (vi->xattr_isize == sizeof(struct erofs_xattr_ibody_header)) {
- errln("xattr_isize %d of nid %llu is not supported yet",
- vi->xattr_isize, vi->nid);
- ret = -ENOTSUPP;
- goto out_unlock;
- } else if (vi->xattr_isize < sizeof(struct erofs_xattr_ibody_header)) {
- if (unlikely(vi->xattr_isize)) {
- DBG_BUGON(1);
- ret = -EIO;
- goto out_unlock; /* xattr ondisk layout error */
- }
- ret = -ENOATTR;
- goto out_unlock;
- }
-
- sb = inode->i_sb;
- sbi = EROFS_SB(sb);
- it.blkaddr = erofs_blknr(iloc(sbi, vi->nid) + vi->inode_isize);
- it.ofs = erofs_blkoff(iloc(sbi, vi->nid) + vi->inode_isize);
-
- it.page = erofs_get_inline_page(inode, it.blkaddr);
- if (IS_ERR(it.page)) {
- ret = PTR_ERR(it.page);
- goto out_unlock;
- }
-
- /* read in shared xattr array (non-atomic, see kmalloc below) */
- it.kaddr = kmap(it.page);
- atomic_map = false;
-
- ih = (struct erofs_xattr_ibody_header *)(it.kaddr + it.ofs);
-
- vi->xattr_shared_count = ih->h_shared_count;
- vi->xattr_shared_xattrs = kmalloc_array(vi->xattr_shared_count,
- sizeof(uint), GFP_KERNEL);
- if (!vi->xattr_shared_xattrs) {
- xattr_iter_end(&it, atomic_map);
- ret = -ENOMEM;
- goto out_unlock;
- }
-
- /* let's skip ibody header */
- it.ofs += sizeof(struct erofs_xattr_ibody_header);
-
- for (i = 0; i < vi->xattr_shared_count; ++i) {
- if (unlikely(it.ofs >= EROFS_BLKSIZ)) {
- /* cannot be unaligned */
- BUG_ON(it.ofs != EROFS_BLKSIZ);
- xattr_iter_end(&it, atomic_map);
-
- it.page = erofs_get_meta_page(sb, ++it.blkaddr,
- S_ISDIR(inode->i_mode));
- if (IS_ERR(it.page)) {
- kfree(vi->xattr_shared_xattrs);
- vi->xattr_shared_xattrs = NULL;
- ret = PTR_ERR(it.page);
- goto out_unlock;
- }
-
- it.kaddr = kmap_atomic(it.page);
- atomic_map = true;
- it.ofs = 0;
- }
- vi->xattr_shared_xattrs[i] =
- le32_to_cpu(*(__le32 *)(it.kaddr + it.ofs));
- it.ofs += sizeof(__le32);
- }
- xattr_iter_end(&it, atomic_map);
-
- set_bit(EROFS_V_EA_INITED_BIT, &vi->flags);
-
-out_unlock:
- clear_and_wake_up_bit(EROFS_V_BL_XATTR_BIT, &vi->flags);
- return ret;
-}
-
-/*
- * the general idea for these return values is
- * if 0 is returned, go on processing the current xattr;
- * 1 (> 0) is returned, skip this round to process the next xattr;
- * -err (< 0) is returned, an error (maybe ENOXATTR) occurred
- * and need to be handled
- */
-struct xattr_iter_handlers {
- int (*entry)(struct xattr_iter *_it, struct erofs_xattr_entry *entry);
- int (*name)(struct xattr_iter *_it, unsigned int processed, char *buf,
- unsigned int len);
- int (*alloc_buffer)(struct xattr_iter *_it, unsigned int value_sz);
- void (*value)(struct xattr_iter *_it, unsigned int processed, char *buf,
- unsigned int len);
-};
-
-static inline int xattr_iter_fixup(struct xattr_iter *it)
-{
- if (it->ofs < EROFS_BLKSIZ)
- return 0;
-
- xattr_iter_end(it, true);
-
- it->blkaddr += erofs_blknr(it->ofs);
-
- it->page = erofs_get_meta_page(it->sb, it->blkaddr, false);
- if (IS_ERR(it->page)) {
- int err = PTR_ERR(it->page);
-
- it->page = NULL;
- return err;
- }
-
- it->kaddr = kmap_atomic(it->page);
- it->ofs = erofs_blkoff(it->ofs);
- return 0;
-}
-
-static int inline_xattr_iter_begin(struct xattr_iter *it,
- struct inode *inode)
-{
- struct erofs_vnode *const vi = EROFS_V(inode);
- struct erofs_sb_info *const sbi = EROFS_SB(inode->i_sb);
- unsigned int xattr_header_sz, inline_xattr_ofs;
-
- xattr_header_sz = inlinexattr_header_size(inode);
- if (unlikely(xattr_header_sz >= vi->xattr_isize)) {
- BUG_ON(xattr_header_sz > vi->xattr_isize);
- return -ENOATTR;
- }
-
- inline_xattr_ofs = vi->inode_isize + xattr_header_sz;
-
- it->blkaddr = erofs_blknr(iloc(sbi, vi->nid) + inline_xattr_ofs);
- it->ofs = erofs_blkoff(iloc(sbi, vi->nid) + inline_xattr_ofs);
-
- it->page = erofs_get_inline_page(inode, it->blkaddr);
- if (IS_ERR(it->page))
- return PTR_ERR(it->page);
-
- it->kaddr = kmap_atomic(it->page);
- return vi->xattr_isize - xattr_header_sz;
-}
-
-/*
- * Regardless of success or failure, `xattr_foreach' will end up with
- * `ofs' pointing to the next xattr item rather than an arbitrary position.
- */
-static int xattr_foreach(struct xattr_iter *it,
- const struct xattr_iter_handlers *op,
- unsigned int *tlimit)
-{
- struct erofs_xattr_entry entry;
- unsigned int value_sz, processed, slice;
- int err;
-
- /* 0. fixup blkaddr, ofs, ipage */
- err = xattr_iter_fixup(it);
- if (err)
- return err;
-
- /*
- * 1. read xattr entry to the memory,
- * since we do EROFS_XATTR_ALIGN
- * therefore entry should be in the page
- */
- entry = *(struct erofs_xattr_entry *)(it->kaddr + it->ofs);
- if (tlimit) {
- unsigned int entry_sz = EROFS_XATTR_ENTRY_SIZE(&entry);
-
- BUG_ON(*tlimit < entry_sz);
- *tlimit -= entry_sz;
- }
-
- it->ofs += sizeof(struct erofs_xattr_entry);
- value_sz = le16_to_cpu(entry.e_value_size);
-
- /* handle entry */
- err = op->entry(it, &entry);
- if (err) {
- it->ofs += entry.e_name_len + value_sz;
- goto out;
- }
-
- /* 2. handle xattr name (ofs will finally be at the end of name) */
- processed = 0;
-
- while (processed < entry.e_name_len) {
- if (it->ofs >= EROFS_BLKSIZ) {
- BUG_ON(it->ofs > EROFS_BLKSIZ);
-
- err = xattr_iter_fixup(it);
- if (err)
- goto out;
- it->ofs = 0;
- }
-
- slice = min_t(unsigned int, PAGE_SIZE - it->ofs,
- entry.e_name_len - processed);
-
- /* handle name */
- err = op->name(it, processed, it->kaddr + it->ofs, slice);
- if (err) {
- it->ofs += entry.e_name_len - processed + value_sz;
- goto out;
- }
-
- it->ofs += slice;
- processed += slice;
- }
-
- /* 3. handle xattr value */
- processed = 0;
-
- if (op->alloc_buffer) {
- err = op->alloc_buffer(it, value_sz);
- if (err) {
- it->ofs += value_sz;
- goto out;
- }
- }
-
- while (processed < value_sz) {
- if (it->ofs >= EROFS_BLKSIZ) {
- BUG_ON(it->ofs > EROFS_BLKSIZ);
-
- err = xattr_iter_fixup(it);
- if (err)
- goto out;
- it->ofs = 0;
- }
-
- slice = min_t(unsigned int, PAGE_SIZE - it->ofs,
- value_sz - processed);
- op->value(it, processed, it->kaddr + it->ofs, slice);
- it->ofs += slice;
- processed += slice;
- }
-
-out:
- /* xattrs should be 4-byte aligned (on-disk constraint) */
- it->ofs = EROFS_XATTR_ALIGN(it->ofs);
- return err < 0 ? err : 0;
-}
-
-struct getxattr_iter {
- struct xattr_iter it;
-
- char *buffer;
- int buffer_size, index;
- struct qstr name;
-};
-
-static int xattr_entrymatch(struct xattr_iter *_it,
- struct erofs_xattr_entry *entry)
-{
- struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
-
- return (it->index != entry->e_name_index ||
- it->name.len != entry->e_name_len) ? -ENOATTR : 0;
-}
-
-static int xattr_namematch(struct xattr_iter *_it,
- unsigned int processed, char *buf, unsigned int len)
-{
- struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
-
- return memcmp(buf, it->name.name + processed, len) ? -ENOATTR : 0;
-}
-
-static int xattr_checkbuffer(struct xattr_iter *_it,
- unsigned int value_sz)
-{
- struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
- int err = it->buffer_size < value_sz ? -ERANGE : 0;
-
- it->buffer_size = value_sz;
- return !it->buffer ? 1 : err;
-}
-
-static void xattr_copyvalue(struct xattr_iter *_it,
- unsigned int processed,
- char *buf, unsigned int len)
-{
- struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
-
- memcpy(it->buffer + processed, buf, len);
-}
-
-static const struct xattr_iter_handlers find_xattr_handlers = {
- .entry = xattr_entrymatch,
- .name = xattr_namematch,
- .alloc_buffer = xattr_checkbuffer,
- .value = xattr_copyvalue
-};
-
-static int inline_getxattr(struct inode *inode, struct getxattr_iter *it)
-{
- int ret;
- unsigned int remaining;
-
- ret = inline_xattr_iter_begin(&it->it, inode);
- if (ret < 0)
- return ret;
-
- remaining = ret;
- while (remaining) {
- ret = xattr_foreach(&it->it, &find_xattr_handlers, &remaining);
- if (ret != -ENOATTR)
- break;
- }
- xattr_iter_end_final(&it->it);
-
- return ret ? ret : it->buffer_size;
-}
-
-static int shared_getxattr(struct inode *inode, struct getxattr_iter *it)
-{
- struct erofs_vnode *const vi = EROFS_V(inode);
- struct super_block *const sb = inode->i_sb;
- struct erofs_sb_info *const sbi = EROFS_SB(sb);
- unsigned int i;
- int ret = -ENOATTR;
-
- for (i = 0; i < vi->xattr_shared_count; ++i) {
- erofs_blk_t blkaddr =
- xattrblock_addr(sbi, vi->xattr_shared_xattrs[i]);
-
- it->it.ofs = xattrblock_offset(sbi, vi->xattr_shared_xattrs[i]);
-
- if (!i || blkaddr != it->it.blkaddr) {
- if (i)
- xattr_iter_end(&it->it, true);
-
- it->it.page = erofs_get_meta_page(sb, blkaddr, false);
- if (IS_ERR(it->it.page))
- return PTR_ERR(it->it.page);
-
- it->it.kaddr = kmap_atomic(it->it.page);
- it->it.blkaddr = blkaddr;
- }
-
- ret = xattr_foreach(&it->it, &find_xattr_handlers, NULL);
- if (ret != -ENOATTR)
- break;
- }
- if (vi->xattr_shared_count)
- xattr_iter_end_final(&it->it);
-
- return ret ? ret : it->buffer_size;
-}
-
-static bool erofs_xattr_user_list(struct dentry *dentry)
-{
- return test_opt(EROFS_SB(dentry->d_sb), XATTR_USER);
-}
-
-static bool erofs_xattr_trusted_list(struct dentry *dentry)
-{
- return capable(CAP_SYS_ADMIN);
-}
-
-int erofs_getxattr(struct inode *inode, int index,
- const char *name,
- void *buffer, size_t buffer_size)
-{
- int ret;
- struct getxattr_iter it;
-
- if (unlikely(!name))
- return -EINVAL;
-
- ret = init_inode_xattrs(inode);
- if (ret)
- return ret;
-
- it.index = index;
-
- it.name.len = strlen(name);
- if (it.name.len > EROFS_NAME_LEN)
- return -ERANGE;
- it.name.name = name;
-
- it.buffer = buffer;
- it.buffer_size = buffer_size;
-
- it.it.sb = inode->i_sb;
- ret = inline_getxattr(inode, &it);
- if (ret == -ENOATTR)
- ret = shared_getxattr(inode, &it);
- return ret;
-}
-
-static int erofs_xattr_generic_get(const struct xattr_handler *handler,
- struct dentry *unused, struct inode *inode,
- const char *name, void *buffer, size_t size)
-{
- struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
-
- switch (handler->flags) {
- case EROFS_XATTR_INDEX_USER:
- if (!test_opt(sbi, XATTR_USER))
- return -EOPNOTSUPP;
- break;
- case EROFS_XATTR_INDEX_TRUSTED:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- break;
- case EROFS_XATTR_INDEX_SECURITY:
- break;
- default:
- return -EINVAL;
- }
-
- return erofs_getxattr(inode, handler->flags, name, buffer, size);
-}
-
-const struct xattr_handler erofs_xattr_user_handler = {
- .prefix = XATTR_USER_PREFIX,
- .flags = EROFS_XATTR_INDEX_USER,
- .list = erofs_xattr_user_list,
- .get = erofs_xattr_generic_get,
-};
-
-const struct xattr_handler erofs_xattr_trusted_handler = {
- .prefix = XATTR_TRUSTED_PREFIX,
- .flags = EROFS_XATTR_INDEX_TRUSTED,
- .list = erofs_xattr_trusted_list,
- .get = erofs_xattr_generic_get,
-};
-
-#ifdef CONFIG_EROFS_FS_SECURITY
-const struct xattr_handler __maybe_unused erofs_xattr_security_handler = {
- .prefix = XATTR_SECURITY_PREFIX,
- .flags = EROFS_XATTR_INDEX_SECURITY,
- .get = erofs_xattr_generic_get,
-};
-#endif
-
-const struct xattr_handler *erofs_xattr_handlers[] = {
- &erofs_xattr_user_handler,
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
- &posix_acl_access_xattr_handler,
- &posix_acl_default_xattr_handler,
-#endif
- &erofs_xattr_trusted_handler,
-#ifdef CONFIG_EROFS_FS_SECURITY
- &erofs_xattr_security_handler,
-#endif
- NULL,
-};
-
-struct listxattr_iter {
- struct xattr_iter it;
-
- struct dentry *dentry;
- char *buffer;
- int buffer_size, buffer_ofs;
-};
-
-static int xattr_entrylist(struct xattr_iter *_it,
- struct erofs_xattr_entry *entry)
-{
- struct listxattr_iter *it =
- container_of(_it, struct listxattr_iter, it);
- unsigned int prefix_len;
- const char *prefix;
-
- const struct xattr_handler *h =
- erofs_xattr_handler(entry->e_name_index);
-
- if (!h || (h->list && !h->list(it->dentry)))
- return 1;
-
- prefix = xattr_prefix(h);
- prefix_len = strlen(prefix);
-
- if (!it->buffer) {
- it->buffer_ofs += prefix_len + entry->e_name_len + 1;
- return 1;
- }
-
- if (it->buffer_ofs + prefix_len
- + entry->e_name_len + 1 > it->buffer_size)
- return -ERANGE;
-
- memcpy(it->buffer + it->buffer_ofs, prefix, prefix_len);
- it->buffer_ofs += prefix_len;
- return 0;
-}
-
-static int xattr_namelist(struct xattr_iter *_it,
- unsigned int processed, char *buf, unsigned int len)
-{
- struct listxattr_iter *it =
- container_of(_it, struct listxattr_iter, it);
-
- memcpy(it->buffer + it->buffer_ofs, buf, len);
- it->buffer_ofs += len;
- return 0;
-}
-
-static int xattr_skipvalue(struct xattr_iter *_it,
- unsigned int value_sz)
-{
- struct listxattr_iter *it =
- container_of(_it, struct listxattr_iter, it);
-
- it->buffer[it->buffer_ofs++] = '\0';
- return 1;
-}
-
-static const struct xattr_iter_handlers list_xattr_handlers = {
- .entry = xattr_entrylist,
- .name = xattr_namelist,
- .alloc_buffer = xattr_skipvalue,
- .value = NULL
-};
-
-static int inline_listxattr(struct listxattr_iter *it)
-{
- int ret;
- unsigned int remaining;
-
- ret = inline_xattr_iter_begin(&it->it, d_inode(it->dentry));
- if (ret < 0)
- return ret;
-
- remaining = ret;
- while (remaining) {
- ret = xattr_foreach(&it->it, &list_xattr_handlers, &remaining);
- if (ret)
- break;
- }
- xattr_iter_end_final(&it->it);
- return ret ? ret : it->buffer_ofs;
-}
-
-static int shared_listxattr(struct listxattr_iter *it)
-{
- struct inode *const inode = d_inode(it->dentry);
- struct erofs_vnode *const vi = EROFS_V(inode);
- struct super_block *const sb = inode->i_sb;
- struct erofs_sb_info *const sbi = EROFS_SB(sb);
- unsigned int i;
- int ret = 0;
-
- for (i = 0; i < vi->xattr_shared_count; ++i) {
- erofs_blk_t blkaddr =
- xattrblock_addr(sbi, vi->xattr_shared_xattrs[i]);
-
- it->it.ofs = xattrblock_offset(sbi, vi->xattr_shared_xattrs[i]);
- if (!i || blkaddr != it->it.blkaddr) {
- if (i)
- xattr_iter_end(&it->it, true);
-
- it->it.page = erofs_get_meta_page(sb, blkaddr, false);
- if (IS_ERR(it->it.page))
- return PTR_ERR(it->it.page);
-
- it->it.kaddr = kmap_atomic(it->it.page);
- it->it.blkaddr = blkaddr;
- }
-
- ret = xattr_foreach(&it->it, &list_xattr_handlers, NULL);
- if (ret)
- break;
- }
- if (vi->xattr_shared_count)
- xattr_iter_end_final(&it->it);
-
- return ret ? ret : it->buffer_ofs;
-}
-
-ssize_t erofs_listxattr(struct dentry *dentry,
- char *buffer, size_t buffer_size)
-{
- int ret;
- struct listxattr_iter it;
-
- ret = init_inode_xattrs(d_inode(dentry));
- if (ret)
- return ret;
-
- it.dentry = dentry;
- it.buffer = buffer;
- it.buffer_size = buffer_size;
- it.buffer_ofs = 0;
-
- it.it.sb = dentry->d_sb;
-
- ret = inline_listxattr(&it);
- if (ret < 0 && ret != -ENOATTR)
- return ret;
- return shared_listxattr(&it);
-}
-
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
-struct posix_acl *erofs_get_acl(struct inode *inode, int type)
-{
- struct posix_acl *acl;
- int prefix, rc;
- char *value = NULL;
-
- switch (type) {
- case ACL_TYPE_ACCESS:
- prefix = EROFS_XATTR_INDEX_POSIX_ACL_ACCESS;
- break;
- case ACL_TYPE_DEFAULT:
- prefix = EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT;
- break;
- default:
- return ERR_PTR(-EINVAL);
- }
-
- rc = erofs_getxattr(inode, prefix, "", NULL, 0);
- if (rc > 0) {
- value = kmalloc(rc, GFP_KERNEL);
- if (!value)
- return ERR_PTR(-ENOMEM);
- rc = erofs_getxattr(inode, prefix, "", value, rc);
- }
-
- if (rc == -ENOATTR)
- acl = NULL;
- else if (rc < 0)
- acl = ERR_PTR(rc);
- else
- acl = posix_acl_from_xattr(&init_user_ns, value, rc);
- kfree(value);
- return acl;
-}
-#endif
-
diff --git a/drivers/staging/erofs/xattr.h b/drivers/staging/erofs/xattr.h
deleted file mode 100644
index 35ba5ac2139a..000000000000
--- a/drivers/staging/erofs/xattr.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * linux/drivers/staging/erofs/xattr.h
- *
- * Copyright (C) 2017-2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#ifndef __EROFS_XATTR_H
-#define __EROFS_XATTR_H
-
-#include "internal.h"
-#include <linux/posix_acl_xattr.h>
-#include <linux/xattr.h>
-
-/* Attribute not found */
-#define ENOATTR ENODATA
-
-static inline unsigned inlinexattr_header_size(struct inode *inode)
-{
- return sizeof(struct erofs_xattr_ibody_header)
- + sizeof(u32) * EROFS_V(inode)->xattr_shared_count;
-}
-
-static inline erofs_blk_t
-xattrblock_addr(struct erofs_sb_info *sbi, unsigned xattr_id)
-{
-#ifdef CONFIG_EROFS_FS_XATTR
- return sbi->xattr_blkaddr +
- xattr_id * sizeof(__u32) / EROFS_BLKSIZ;
-#else
- return 0;
-#endif
-}
-
-static inline unsigned
-xattrblock_offset(struct erofs_sb_info *sbi, unsigned xattr_id)
-{
- return (xattr_id * sizeof(__u32)) % EROFS_BLKSIZ;
-}
-
-extern const struct xattr_handler erofs_xattr_user_handler;
-extern const struct xattr_handler erofs_xattr_trusted_handler;
-#ifdef CONFIG_EROFS_FS_SECURITY
-extern const struct xattr_handler erofs_xattr_security_handler;
-#endif
-
-static inline const struct xattr_handler *erofs_xattr_handler(unsigned index)
-{
-static const struct xattr_handler *xattr_handler_map[] = {
- [EROFS_XATTR_INDEX_USER] = &erofs_xattr_user_handler,
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
- [EROFS_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler,
- [EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT] =
- &posix_acl_default_xattr_handler,
-#endif
- [EROFS_XATTR_INDEX_TRUSTED] = &erofs_xattr_trusted_handler,
-#ifdef CONFIG_EROFS_FS_SECURITY
- [EROFS_XATTR_INDEX_SECURITY] = &erofs_xattr_security_handler,
-#endif
-};
- return index && index < ARRAY_SIZE(xattr_handler_map) ?
- xattr_handler_map[index] : NULL;
-}
-
-#ifdef CONFIG_EROFS_FS_XATTR
-extern const struct xattr_handler *erofs_xattr_handlers[];
-
-int erofs_getxattr(struct inode *, int, const char *, void *, size_t);
-ssize_t erofs_listxattr(struct dentry *, char *, size_t);
-#else
-static int __maybe_unused erofs_getxattr(struct inode *inode, int index,
- const char *name,
- void *buffer, size_t buffer_size)
-{
- return -ENOTSUPP;
-}
-
-static ssize_t __maybe_unused erofs_listxattr(struct dentry *dentry,
- char *buffer, size_t buffer_size)
-{
- return -ENOTSUPP;
-}
-#endif
-
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
-struct posix_acl *erofs_get_acl(struct inode *inode, int type);
-#else
-#define erofs_get_acl (NULL)
-#endif
-
-#endif
-
diff --git a/drivers/staging/erofs/zmap.c b/drivers/staging/erofs/zmap.c
deleted file mode 100644
index 9c0bd65c46bf..000000000000
--- a/drivers/staging/erofs/zmap.c
+++ /dev/null
@@ -1,463 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/zmap.c
- *
- * Copyright (C) 2018-2019 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- */
-#include "internal.h"
-#include <asm/unaligned.h>
-#include <trace/events/erofs.h>
-
-int z_erofs_fill_inode(struct inode *inode)
-{
- struct erofs_vnode *const vi = EROFS_V(inode);
- struct super_block *const sb = inode->i_sb;
-
- if (vi->datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
- vi->z_advise = 0;
- vi->z_algorithmtype[0] = 0;
- vi->z_algorithmtype[1] = 0;
- vi->z_logical_clusterbits = EROFS_SB(sb)->clusterbits;
- vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits;
- vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits;
- set_bit(EROFS_V_Z_INITED_BIT, &vi->flags);
- }
-
- inode->i_mapping->a_ops = &z_erofs_vle_normalaccess_aops;
- return 0;
-}
-
-static int fill_inode_lazy(struct inode *inode)
-{
- struct erofs_vnode *const vi = EROFS_V(inode);
- struct super_block *const sb = inode->i_sb;
- int err;
- erofs_off_t pos;
- struct page *page;
- void *kaddr;
- struct z_erofs_map_header *h;
-
- if (test_bit(EROFS_V_Z_INITED_BIT, &vi->flags))
- return 0;
-
- if (wait_on_bit_lock(&vi->flags, EROFS_V_BL_Z_BIT, TASK_KILLABLE))
- return -ERESTARTSYS;
-
- err = 0;
- if (test_bit(EROFS_V_Z_INITED_BIT, &vi->flags))
- goto out_unlock;
-
- DBG_BUGON(vi->datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
-
- pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize +
- vi->xattr_isize, 8);
- page = erofs_get_meta_page(sb, erofs_blknr(pos), false);
- if (IS_ERR(page)) {
- err = PTR_ERR(page);
- goto out_unlock;
- }
-
- kaddr = kmap_atomic(page);
-
- h = kaddr + erofs_blkoff(pos);
- vi->z_advise = le16_to_cpu(h->h_advise);
- vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
- vi->z_algorithmtype[1] = h->h_algorithmtype >> 4;
-
- if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX) {
- errln("unknown compression format %u for nid %llu, please upgrade kernel",
- vi->z_algorithmtype[0], vi->nid);
- err = -ENOTSUPP;
- goto unmap_done;
- }
-
- vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7);
- vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits +
- ((h->h_clusterbits >> 3) & 3);
-
- if (vi->z_physical_clusterbits[0] != LOG_BLOCK_SIZE) {
- errln("unsupported physical clusterbits %u for nid %llu, please upgrade kernel",
- vi->z_physical_clusterbits[0], vi->nid);
- err = -ENOTSUPP;
- goto unmap_done;
- }
-
- vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits +
- ((h->h_clusterbits >> 5) & 7);
-unmap_done:
- kunmap_atomic(kaddr);
- unlock_page(page);
- put_page(page);
-
- set_bit(EROFS_V_Z_INITED_BIT, &vi->flags);
-out_unlock:
- clear_and_wake_up_bit(EROFS_V_BL_Z_BIT, &vi->flags);
- return err;
-}
-
-struct z_erofs_maprecorder {
- struct inode *inode;
- struct erofs_map_blocks *map;
- void *kaddr;
-
- unsigned long lcn;
- /* compression extent information gathered */
- u8 type;
- u16 clusterofs;
- u16 delta[2];
- erofs_blk_t pblk;
-};
-
-static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
- erofs_blk_t eblk)
-{
- struct super_block *const sb = m->inode->i_sb;
- struct erofs_map_blocks *const map = m->map;
- struct page *mpage = map->mpage;
-
- if (mpage) {
- if (mpage->index == eblk) {
- if (!m->kaddr)
- m->kaddr = kmap_atomic(mpage);
- return 0;
- }
-
- if (m->kaddr) {
- kunmap_atomic(m->kaddr);
- m->kaddr = NULL;
- }
- put_page(mpage);
- }
-
- mpage = erofs_get_meta_page(sb, eblk, false);
- if (IS_ERR(mpage)) {
- map->mpage = NULL;
- return PTR_ERR(mpage);
- }
- m->kaddr = kmap_atomic(mpage);
- unlock_page(mpage);
- map->mpage = mpage;
- return 0;
-}
-
-static int vle_legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
- unsigned long lcn)
-{
- struct inode *const inode = m->inode;
- struct erofs_vnode *const vi = EROFS_V(inode);
- const erofs_off_t ibase = iloc(EROFS_I_SB(inode), vi->nid);
- const erofs_off_t pos =
- Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize +
- vi->xattr_isize) +
- lcn * sizeof(struct z_erofs_vle_decompressed_index);
- struct z_erofs_vle_decompressed_index *di;
- unsigned int advise, type;
- int err;
-
- err = z_erofs_reload_indexes(m, erofs_blknr(pos));
- if (err)
- return err;
-
- m->lcn = lcn;
- di = m->kaddr + erofs_blkoff(pos);
-
- advise = le16_to_cpu(di->di_advise);
- type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) &
- ((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1);
- switch (type) {
- case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
- m->clusterofs = 1 << vi->z_logical_clusterbits;
- m->delta[0] = le16_to_cpu(di->di_u.delta[0]);
- m->delta[1] = le16_to_cpu(di->di_u.delta[1]);
- break;
- case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
- case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
- m->clusterofs = le16_to_cpu(di->di_clusterofs);
- m->pblk = le32_to_cpu(di->di_u.blkaddr);
- break;
- default:
- DBG_BUGON(1);
- return -EIO;
- }
- m->type = type;
- return 0;
-}
-
-static unsigned int decode_compactedbits(unsigned int lobits,
- unsigned int lomask,
- u8 *in, unsigned int pos, u8 *type)
-{
- const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7);
- const unsigned int lo = v & lomask;
-
- *type = (v >> lobits) & 3;
- return lo;
-}
-
-static int unpack_compacted_index(struct z_erofs_maprecorder *m,
- unsigned int amortizedshift,
- unsigned int eofs)
-{
- struct erofs_vnode *const vi = EROFS_V(m->inode);
- const unsigned int lclusterbits = vi->z_logical_clusterbits;
- const unsigned int lomask = (1 << lclusterbits) - 1;
- unsigned int vcnt, base, lo, encodebits, nblk;
- int i;
- u8 *in, type;
-
- if (1 << amortizedshift == 4)
- vcnt = 2;
- else if (1 << amortizedshift == 2 && lclusterbits == 12)
- vcnt = 16;
- else
- return -ENOTSUPP;
-
- encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt;
- base = round_down(eofs, vcnt << amortizedshift);
- in = m->kaddr + base;
-
- i = (eofs - base) >> amortizedshift;
-
- lo = decode_compactedbits(lclusterbits, lomask,
- in, encodebits * i, &type);
- m->type = type;
- if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
- m->clusterofs = 1 << lclusterbits;
- if (i + 1 != vcnt) {
- m->delta[0] = lo;
- return 0;
- }
- /*
- * since the last lcluster in the pack is special,
- * of which lo saves delta[1] rather than delta[0].
- * Hence, get delta[0] by the previous lcluster indirectly.
- */
- lo = decode_compactedbits(lclusterbits, lomask,
- in, encodebits * (i - 1), &type);
- if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
- lo = 0;
- m->delta[0] = lo + 1;
- return 0;
- }
- m->clusterofs = lo;
- m->delta[0] = 0;
- /* figout out blkaddr (pblk) for HEAD lclusters */
- nblk = 1;
- while (i > 0) {
- --i;
- lo = decode_compactedbits(lclusterbits, lomask,
- in, encodebits * i, &type);
- if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
- i -= lo;
-
- if (i >= 0)
- ++nblk;
- }
- in += (vcnt << amortizedshift) - sizeof(__le32);
- m->pblk = le32_to_cpu(*(__le32 *)in) + nblk;
- return 0;
-}
-
-static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
- unsigned long lcn)
-{
- struct inode *const inode = m->inode;
- struct erofs_vnode *const vi = EROFS_V(inode);
- const unsigned int lclusterbits = vi->z_logical_clusterbits;
- const erofs_off_t ebase = ALIGN(iloc(EROFS_I_SB(inode), vi->nid) +
- vi->inode_isize + vi->xattr_isize, 8) +
- sizeof(struct z_erofs_map_header);
- const unsigned int totalidx = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
- unsigned int compacted_4b_initial, compacted_2b;
- unsigned int amortizedshift;
- erofs_off_t pos;
- int err;
-
- if (lclusterbits != 12)
- return -ENOTSUPP;
-
- if (lcn >= totalidx)
- return -EINVAL;
-
- m->lcn = lcn;
- /* used to align to 32-byte (compacted_2b) alignment */
- compacted_4b_initial = (32 - ebase % 32) / 4;
- if (compacted_4b_initial == 32 / 4)
- compacted_4b_initial = 0;
-
- if (vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B)
- compacted_2b = rounddown(totalidx - compacted_4b_initial, 16);
- else
- compacted_2b = 0;
-
- pos = ebase;
- if (lcn < compacted_4b_initial) {
- amortizedshift = 2;
- goto out;
- }
- pos += compacted_4b_initial * 4;
- lcn -= compacted_4b_initial;
-
- if (lcn < compacted_2b) {
- amortizedshift = 1;
- goto out;
- }
- pos += compacted_2b * 2;
- lcn -= compacted_2b;
- amortizedshift = 2;
-out:
- pos += lcn * (1 << amortizedshift);
- err = z_erofs_reload_indexes(m, erofs_blknr(pos));
- if (err)
- return err;
- return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos));
-}
-
-static int vle_load_cluster_from_disk(struct z_erofs_maprecorder *m,
- unsigned int lcn)
-{
- const unsigned int datamode = EROFS_V(m->inode)->datamode;
-
- if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
- return vle_legacy_load_cluster_from_disk(m, lcn);
-
- if (datamode == EROFS_INODE_FLAT_COMPRESSION)
- return compacted_load_cluster_from_disk(m, lcn);
-
- return -EINVAL;
-}
-
-static int vle_extent_lookback(struct z_erofs_maprecorder *m,
- unsigned int lookback_distance)
-{
- struct erofs_vnode *const vi = EROFS_V(m->inode);
- struct erofs_map_blocks *const map = m->map;
- const unsigned int lclusterbits = vi->z_logical_clusterbits;
- unsigned long lcn = m->lcn;
- int err;
-
- if (lcn < lookback_distance) {
- DBG_BUGON(1);
- return -EIO;
- }
-
- /* load extent head logical cluster if needed */
- lcn -= lookback_distance;
- err = vle_load_cluster_from_disk(m, lcn);
- if (err)
- return err;
-
- switch (m->type) {
- case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
- return vle_extent_lookback(m, m->delta[0]);
- case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
- map->m_flags &= ~EROFS_MAP_ZIPPED;
- /* fallthrough */
- case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
- map->m_la = (lcn << lclusterbits) | m->clusterofs;
- break;
- default:
- errln("unknown type %u at lcn %lu of nid %llu",
- m->type, lcn, vi->nid);
- DBG_BUGON(1);
- return -EIO;
- }
- return 0;
-}
-
-int z_erofs_map_blocks_iter(struct inode *inode,
- struct erofs_map_blocks *map,
- int flags)
-{
- struct erofs_vnode *const vi = EROFS_V(inode);
- struct z_erofs_maprecorder m = {
- .inode = inode,
- .map = map,
- };
- int err = 0;
- unsigned int lclusterbits, endoff;
- unsigned long long ofs, end;
-
- trace_z_erofs_map_blocks_iter_enter(inode, map, flags);
-
- /* when trying to read beyond EOF, leave it unmapped */
- if (unlikely(map->m_la >= inode->i_size)) {
- map->m_llen = map->m_la + 1 - inode->i_size;
- map->m_la = inode->i_size;
- map->m_flags = 0;
- goto out;
- }
-
- err = fill_inode_lazy(inode);
- if (err)
- goto out;
-
- lclusterbits = vi->z_logical_clusterbits;
- ofs = map->m_la;
- m.lcn = ofs >> lclusterbits;
- endoff = ofs & ((1 << lclusterbits) - 1);
-
- err = vle_load_cluster_from_disk(&m, m.lcn);
- if (err)
- goto unmap_out;
-
- map->m_flags = EROFS_MAP_ZIPPED; /* by default, compressed */
- end = (m.lcn + 1ULL) << lclusterbits;
-
- switch (m.type) {
- case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
- if (endoff >= m.clusterofs)
- map->m_flags &= ~EROFS_MAP_ZIPPED;
- /* fallthrough */
- case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
- if (endoff >= m.clusterofs) {
- map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
- break;
- }
- /* m.lcn should be >= 1 if endoff < m.clusterofs */
- if (unlikely(!m.lcn)) {
- errln("invalid logical cluster 0 at nid %llu",
- vi->nid);
- err = -EIO;
- goto unmap_out;
- }
- end = (m.lcn << lclusterbits) | m.clusterofs;
- map->m_flags |= EROFS_MAP_FULL_MAPPED;
- m.delta[0] = 1;
- /* fallthrough */
- case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
- /* get the correspoinding first chunk */
- err = vle_extent_lookback(&m, m.delta[0]);
- if (unlikely(err))
- goto unmap_out;
- break;
- default:
- errln("unknown type %u at offset %llu of nid %llu",
- m.type, ofs, vi->nid);
- err = -EIO;
- goto unmap_out;
- }
-
- map->m_llen = end - map->m_la;
- map->m_plen = 1 << lclusterbits;
- map->m_pa = blknr_to_addr(m.pblk);
- map->m_flags |= EROFS_MAP_MAPPED;
-
-unmap_out:
- if (m.kaddr)
- kunmap_atomic(m.kaddr);
-
-out:
- debugln("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o",
- __func__, map->m_la, map->m_pa,
- map->m_llen, map->m_plen, map->m_flags);
-
- trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err);
-
- /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */
- DBG_BUGON(err < 0 && err != -ENOMEM);
- return err;
-}
-
diff --git a/drivers/staging/exfat/Kconfig b/drivers/staging/exfat/Kconfig
new file mode 100644
index 000000000000..290dbfc7ace1
--- /dev/null
+++ b/drivers/staging/exfat/Kconfig
@@ -0,0 +1,49 @@
+config EXFAT_FS
+ tristate "exFAT fs support"
+ depends on BLOCK
+ select NLS
+ help
+ This adds support for the exFAT file system.
+
+config EXFAT_DONT_MOUNT_VFAT
+ bool "Prohibit mounting of fat/vfat filesysems by exFAT"
+ depends on EXFAT_FS
+ default y
+ help
+ By default, the exFAT driver will only mount exFAT filesystems, and refuse
+ to mount fat/vfat filesystems. Set this to 'n' to allow the exFAT driver
+ to mount these filesystems.
+
+config EXFAT_DISCARD
+ bool "enable discard support"
+ depends on EXFAT_FS
+ default y
+
+config EXFAT_DELAYED_SYNC
+ bool "enable delayed sync"
+ depends on EXFAT_FS
+ default n
+
+config EXFAT_KERNEL_DEBUG
+ bool "enable kernel debug features via ioctl"
+ depends on EXFAT_FS
+ default n
+
+config EXFAT_DEBUG_MSG
+ bool "print debug messages"
+ depends on EXFAT_FS
+ default n
+
+config EXFAT_DEFAULT_CODEPAGE
+ int "Default codepage for exFAT"
+ default 437
+ depends on EXFAT_FS
+ help
+ This option should be set to the codepage of your exFAT filesystems.
+
+config EXFAT_DEFAULT_IOCHARSET
+ string "Default iocharset for exFAT"
+ default "utf8"
+ depends on EXFAT_FS
+ help
+ Set this to the default input/output character set you'd like exFAT to use.
diff --git a/drivers/staging/exfat/Makefile b/drivers/staging/exfat/Makefile
new file mode 100644
index 000000000000..84944dfbae28
--- /dev/null
+++ b/drivers/staging/exfat/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_EXFAT_FS) += exfat.o
+
+exfat-y := exfat_core.o \
+ exfat_super.o \
+ exfat_blkdev.o \
+ exfat_cache.o \
+ exfat_nls.o \
+ exfat_upcase.o
diff --git a/drivers/staging/exfat/TODO b/drivers/staging/exfat/TODO
new file mode 100644
index 000000000000..a3eb282f9efc
--- /dev/null
+++ b/drivers/staging/exfat/TODO
@@ -0,0 +1,12 @@
+exfat_core.c - ffsReadFile - the goto err_out seem to leak a brelse().
+same for ffsWriteFile.
+
+exfat_core.c - fs_sync(sb,0) all over the place looks fishy as hell.
+There's only one place that calls it with a non-zero argument.
+
+ffsTruncateFile - if (old_size <= new_size) {
+That doesn't look right. How did it ever work? Are they relying on lazy
+block allocation when actual writes happen? If nothing else, it never
+does the 'fid->size = new_size' and do the inode update....
+
+ffsSetAttr() is just dangling in the breeze, not wired up at all...
diff --git a/drivers/staging/exfat/exfat.h b/drivers/staging/exfat/exfat.h
new file mode 100644
index 000000000000..6c12f2d79f4d
--- /dev/null
+++ b/drivers/staging/exfat/exfat.h
@@ -0,0 +1,971 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef _EXFAT_H
+#define _EXFAT_H
+
+#include <linux/types.h>
+#include <linux/buffer_head.h>
+
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ /* For Debugging Purpose */
+ /* IOCTL code 'f' used by
+ * - file systems typically #0~0x1F
+ * - embedded terminal devices #128~
+ * - exts for debugging purpose #99
+ * number 100 and 101 is available now but has possible conflicts
+ */
+#define EXFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long)
+#define EXFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long)
+
+#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01
+#define EXFAT_DEBUGFLAGS_ERROR_RW 0x02
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+#ifdef CONFIG_EXFAT_DEBUG_MSG
+#define DEBUG 1
+#else
+#undef DEBUG
+#endif
+
+#define DENTRY_SIZE 32 /* dir entry size */
+#define DENTRY_SIZE_BITS 5
+
+/* PBR entries */
+#define PBR_SIGNATURE 0xAA55
+#define EXT_SIGNATURE 0xAA550000
+#define VOL_LABEL "NO NAME " /* size should be 11 */
+#define OEM_NAME "MSWIN4.1" /* size should be 8 */
+#define STR_FAT12 "FAT12 " /* size should be 8 */
+#define STR_FAT16 "FAT16 " /* size should be 8 */
+#define STR_FAT32 "FAT32 " /* size should be 8 */
+#define STR_EXFAT "EXFAT " /* size should be 8 */
+#define VOL_CLEAN 0x0000
+#define VOL_DIRTY 0x0002
+
+/* max number of clusters */
+#define FAT12_THRESHOLD 4087 /* 2^12 - 1 + 2 (clu 0 & 1) */
+#define FAT16_THRESHOLD 65527 /* 2^16 - 1 + 2 */
+#define FAT32_THRESHOLD 268435457 /* 2^28 - 1 + 2 */
+#define EXFAT_THRESHOLD 268435457 /* 2^28 - 1 + 2 */
+
+/* file types */
+#define TYPE_UNUSED 0x0000
+#define TYPE_DELETED 0x0001
+#define TYPE_INVALID 0x0002
+#define TYPE_CRITICAL_PRI 0x0100
+#define TYPE_BITMAP 0x0101
+#define TYPE_UPCASE 0x0102
+#define TYPE_VOLUME 0x0103
+#define TYPE_DIR 0x0104
+#define TYPE_FILE 0x011F
+#define TYPE_SYMLINK 0x015F
+#define TYPE_CRITICAL_SEC 0x0200
+#define TYPE_STREAM 0x0201
+#define TYPE_EXTEND 0x0202
+#define TYPE_ACL 0x0203
+#define TYPE_BENIGN_PRI 0x0400
+#define TYPE_GUID 0x0401
+#define TYPE_PADDING 0x0402
+#define TYPE_ACLTAB 0x0403
+#define TYPE_BENIGN_SEC 0x0800
+#define TYPE_ALL 0x0FFF
+
+/* time modes */
+#define TM_CREATE 0
+#define TM_MODIFY 1
+#define TM_ACCESS 2
+
+/* checksum types */
+#define CS_DIR_ENTRY 0
+#define CS_PBR_SECTOR 1
+#define CS_DEFAULT 2
+
+#define CLUSTER_16(x) ((u16)(x))
+#define CLUSTER_32(x) ((u32)(x))
+
+#define START_SECTOR(x) \
+ ((((sector_t)((x) - 2)) << p_fs->sectors_per_clu_bits) + \
+ p_fs->data_start_sector)
+
+#define IS_LAST_SECTOR_IN_CLUSTER(sec) \
+ ((((sec) - p_fs->data_start_sector + 1) & \
+ ((1 << p_fs->sectors_per_clu_bits) - 1)) == 0)
+
+#define GET_CLUSTER_FROM_SECTOR(sec) \
+ ((u32)((((sec) - p_fs->data_start_sector) >> \
+ p_fs->sectors_per_clu_bits) + 2))
+
+#define GET16(p_src) \
+ (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8))
+#define GET32(p_src) \
+ (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) | \
+ (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24))
+#define GET64(p_src) \
+ (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) | \
+ (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \
+ (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \
+ (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56))
+
+#define SET16(p_dst, src) \
+ do { \
+ (p_dst)[0] = (u8)(src); \
+ (p_dst)[1] = (u8)(((u16)(src)) >> 8); \
+ } while (0)
+#define SET32(p_dst, src) \
+ do { \
+ (p_dst)[0] = (u8)(src); \
+ (p_dst)[1] = (u8)(((u32)(src)) >> 8); \
+ (p_dst)[2] = (u8)(((u32)(src)) >> 16); \
+ (p_dst)[3] = (u8)(((u32)(src)) >> 24); \
+ } while (0)
+#define SET64(p_dst, src) \
+ do { \
+ (p_dst)[0] = (u8)(src); \
+ (p_dst)[1] = (u8)(((u64)(src)) >> 8); \
+ (p_dst)[2] = (u8)(((u64)(src)) >> 16); \
+ (p_dst)[3] = (u8)(((u64)(src)) >> 24); \
+ (p_dst)[4] = (u8)(((u64)(src)) >> 32); \
+ (p_dst)[5] = (u8)(((u64)(src)) >> 40); \
+ (p_dst)[6] = (u8)(((u64)(src)) >> 48); \
+ (p_dst)[7] = (u8)(((u64)(src)) >> 56); \
+ } while (0)
+
+#ifdef __LITTLE_ENDIAN
+#define GET16_A(p_src) (*((u16 *)(p_src)))
+#define GET32_A(p_src) (*((u32 *)(p_src)))
+#define GET64_A(p_src) (*((u64 *)(p_src)))
+#define SET16_A(p_dst, src) (*((u16 *)(p_dst)) = (u16)(src))
+#define SET32_A(p_dst, src) (*((u32 *)(p_dst)) = (u32)(src))
+#define SET64_A(p_dst, src) (*((u64 *)(p_dst)) = (u64)(src))
+#else /* BIG_ENDIAN */
+#define GET16_A(p_src) GET16(p_src)
+#define GET32_A(p_src) GET32(p_src)
+#define GET64_A(p_src) GET64(p_src)
+#define SET16_A(p_dst, src) SET16(p_dst, src)
+#define SET32_A(p_dst, src) SET32(p_dst, src)
+#define SET64_A(p_dst, src) SET64(p_dst, src)
+#endif
+
+/* cache size (in number of sectors) */
+/* (should be an exponential value of 2) */
+#define FAT_CACHE_SIZE 128
+#define FAT_CACHE_HASH_SIZE 64
+#define BUF_CACHE_SIZE 256
+#define BUF_CACHE_HASH_SIZE 64
+
+/* Upcase table macro */
+#define HIGH_INDEX_BIT (8)
+#define HIGH_INDEX_MASK (0xFF00)
+#define LOW_INDEX_BIT (16 - HIGH_INDEX_BIT)
+#define UTBL_ROW_COUNT BIT(LOW_INDEX_BIT)
+#define UTBL_COL_COUNT BIT(HIGH_INDEX_BIT)
+
+static inline u16 get_col_index(u16 i)
+{
+ return i >> LOW_INDEX_BIT;
+}
+
+static inline u16 get_row_index(u16 i)
+{
+ return i & ~HIGH_INDEX_MASK;
+}
+
+#define EXFAT_SUPER_MAGIC (0x2011BAB0L)
+#define EXFAT_ROOT_INO 1
+
+/* FAT types */
+#define FAT12 0x01 /* FAT12 */
+#define FAT16 0x0E /* Win95 FAT16 (LBA) */
+#define FAT32 0x0C /* Win95 FAT32 (LBA) */
+#define EXFAT 0x07 /* exFAT */
+
+/* file name lengths */
+#define MAX_CHARSET_SIZE 3 /* max size of multi-byte character */
+#define MAX_PATH_DEPTH 15 /* max depth of path name */
+#define MAX_NAME_LENGTH 256 /* max len of filename including NULL */
+#define MAX_PATH_LENGTH 260 /* max len of pathname including NULL */
+#define DOS_NAME_LENGTH 11 /* DOS filename length excluding NULL */
+#define DOS_PATH_LENGTH 80 /* DOS pathname length excluding NULL */
+
+/* file attributes */
+#define ATTR_NORMAL 0x0000
+#define ATTR_READONLY 0x0001
+#define ATTR_HIDDEN 0x0002
+#define ATTR_SYSTEM 0x0004
+#define ATTR_VOLUME 0x0008
+#define ATTR_SUBDIR 0x0010
+#define ATTR_ARCHIVE 0x0020
+#define ATTR_SYMLINK 0x0040
+#define ATTR_EXTEND 0x000F
+#define ATTR_RWMASK 0x007E
+
+/* file creation modes */
+#define FM_REGULAR 0x00
+#define FM_SYMLINK 0x40
+
+/* return values */
+#define FFS_SUCCESS 0
+#define FFS_MEDIAERR 1
+#define FFS_FORMATERR 2
+#define FFS_MOUNTED 3
+#define FFS_NOTMOUNTED 4
+#define FFS_ALIGNMENTERR 5
+#define FFS_SEMAPHOREERR 6
+#define FFS_INVALIDPATH 7
+#define FFS_INVALIDFID 8
+#define FFS_NOTFOUND 9
+#define FFS_FILEEXIST 10
+#define FFS_PERMISSIONERR 11
+#define FFS_NOTOPENED 12
+#define FFS_MAXOPENED 13
+#define FFS_FULL 14
+#define FFS_EOF 15
+#define FFS_DIRBUSY 16
+#define FFS_MEMORYERR 17
+#define FFS_NAMETOOLONG 18
+#define FFS_ERROR 19
+
+#define NUM_UPCASE 2918
+
+#define DOS_CUR_DIR_NAME ". "
+#define DOS_PAR_DIR_NAME ".. "
+
+#ifdef __LITTLE_ENDIAN
+#define UNI_CUR_DIR_NAME ".\0"
+#define UNI_PAR_DIR_NAME ".\0.\0"
+#else
+#define UNI_CUR_DIR_NAME "\0."
+#define UNI_PAR_DIR_NAME "\0.\0."
+#endif
+
+struct date_time_t {
+ u16 Year;
+ u16 Month;
+ u16 Day;
+ u16 Hour;
+ u16 Minute;
+ u16 Second;
+ u16 MilliSecond;
+};
+
+struct part_info_t {
+ u32 Offset; /* start sector number of the partition */
+ u32 Size; /* in sectors */
+};
+
+struct dev_info_t {
+ u32 SecSize; /* sector size in bytes */
+ u32 DevSize; /* block device size in sectors */
+};
+
+struct vol_info_t {
+ u32 FatType;
+ u32 ClusterSize;
+ u32 NumClusters;
+ u32 FreeClusters;
+ u32 UsedClusters;
+};
+
+/* directory structure */
+struct chain_t {
+ u32 dir;
+ s32 size;
+ u8 flags;
+};
+
+struct file_id_t {
+ struct chain_t dir;
+ s32 entry;
+ u32 type;
+ u32 attr;
+ u32 start_clu;
+ u64 size;
+ u8 flags;
+ s64 rwoffset;
+ s32 hint_last_off;
+ u32 hint_last_clu;
+};
+
+struct dir_entry_t {
+ char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE];
+
+ /* used only for FAT12/16/32, not used for exFAT */
+ char ShortName[DOS_NAME_LENGTH + 2];
+
+ u32 Attr;
+ u64 Size;
+ u32 NumSubdirs;
+ struct date_time_t CreateTimestamp;
+ struct date_time_t ModifyTimestamp;
+ struct date_time_t AccessTimestamp;
+};
+
+struct timestamp_t {
+ u16 sec; /* 0 ~ 59 */
+ u16 min; /* 0 ~ 59 */
+ u16 hour; /* 0 ~ 23 */
+ u16 day; /* 1 ~ 31 */
+ u16 mon; /* 1 ~ 12 */
+ u16 year; /* 0 ~ 127 (since 1980) */
+};
+
+/* MS_DOS FAT partition boot record (512 bytes) */
+struct pbr_sector_t {
+ u8 jmp_boot[3];
+ u8 oem_name[8];
+ u8 bpb[109];
+ u8 boot_code[390];
+ u8 signature[2];
+};
+
+/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */
+struct bpb16_t {
+ u8 sector_size[2];
+ u8 sectors_per_clu;
+ u8 num_reserved[2];
+ u8 num_fats;
+ u8 num_root_entries[2];
+ u8 num_sectors[2];
+ u8 media_type;
+ u8 num_fat_sectors[2];
+ u8 sectors_in_track[2];
+ u8 num_heads[2];
+ u8 num_hid_sectors[4];
+ u8 num_huge_sectors[4];
+
+ u8 phy_drv_no;
+ u8 reserved;
+ u8 ext_signature;
+ u8 vol_serial[4];
+ u8 vol_label[11];
+ u8 vol_type[8];
+};
+
+/* MS-DOS FAT32 BIOS parameter block (79 bytes) */
+struct bpb32_t {
+ u8 sector_size[2];
+ u8 sectors_per_clu;
+ u8 num_reserved[2];
+ u8 num_fats;
+ u8 num_root_entries[2];
+ u8 num_sectors[2];
+ u8 media_type;
+ u8 num_fat_sectors[2];
+ u8 sectors_in_track[2];
+ u8 num_heads[2];
+ u8 num_hid_sectors[4];
+ u8 num_huge_sectors[4];
+ u8 num_fat32_sectors[4];
+ u8 ext_flags[2];
+ u8 fs_version[2];
+ u8 root_cluster[4];
+ u8 fsinfo_sector[2];
+ u8 backup_sector[2];
+ u8 reserved[12];
+
+ u8 phy_drv_no;
+ u8 ext_reserved;
+ u8 ext_signature;
+ u8 vol_serial[4];
+ u8 vol_label[11];
+ u8 vol_type[8];
+};
+
+/* MS-DOS EXFAT BIOS parameter block (109 bytes) */
+struct bpbex_t {
+ u8 reserved1[53];
+ u8 vol_offset[8];
+ u8 vol_length[8];
+ u8 fat_offset[4];
+ u8 fat_length[4];
+ u8 clu_offset[4];
+ u8 clu_count[4];
+ u8 root_cluster[4];
+ u8 vol_serial[4];
+ u8 fs_version[2];
+ u8 vol_flags[2];
+ u8 sector_size_bits;
+ u8 sectors_per_clu_bits;
+ u8 num_fats;
+ u8 phy_drv_no;
+ u8 perc_in_use;
+ u8 reserved2[7];
+};
+
+/* MS-DOS FAT file system information sector (512 bytes) */
+struct fsi_sector_t {
+ u8 signature1[4];
+ u8 reserved1[480];
+ u8 signature2[4];
+ u8 free_cluster[4];
+ u8 next_cluster[4];
+ u8 reserved2[14];
+ u8 signature3[2];
+};
+
+/* MS-DOS FAT directory entry (32 bytes) */
+struct dentry_t {
+ u8 dummy[32];
+};
+
+struct dos_dentry_t {
+ u8 name[DOS_NAME_LENGTH];
+ u8 attr;
+ u8 lcase;
+ u8 create_time_ms;
+ u8 create_time[2];
+ u8 create_date[2];
+ u8 access_date[2];
+ u8 start_clu_hi[2];
+ u8 modify_time[2];
+ u8 modify_date[2];
+ u8 start_clu_lo[2];
+ u8 size[4];
+};
+
+/* MS-DOS FAT extended directory entry (32 bytes) */
+struct ext_dentry_t {
+ u8 order;
+ u8 unicode_0_4[10];
+ u8 attr;
+ u8 sysid;
+ u8 checksum;
+ u8 unicode_5_10[12];
+ u8 start_clu[2];
+ u8 unicode_11_12[4];
+};
+
+/* MS-DOS EXFAT file directory entry (32 bytes) */
+struct file_dentry_t {
+ u8 type;
+ u8 num_ext;
+ u8 checksum[2];
+ u8 attr[2];
+ u8 reserved1[2];
+ u8 create_time[2];
+ u8 create_date[2];
+ u8 modify_time[2];
+ u8 modify_date[2];
+ u8 access_time[2];
+ u8 access_date[2];
+ u8 create_time_ms;
+ u8 modify_time_ms;
+ u8 access_time_ms;
+ u8 reserved2[9];
+};
+
+/* MS-DOS EXFAT stream extension directory entry (32 bytes) */
+struct strm_dentry_t {
+ u8 type;
+ u8 flags;
+ u8 reserved1;
+ u8 name_len;
+ u8 name_hash[2];
+ u8 reserved2[2];
+ u8 valid_size[8];
+ u8 reserved3[4];
+ u8 start_clu[4];
+ u8 size[8];
+};
+
+/* MS-DOS EXFAT file name directory entry (32 bytes) */
+struct name_dentry_t {
+ u8 type;
+ u8 flags;
+ u8 unicode_0_14[30];
+};
+
+/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */
+struct bmap_dentry_t {
+ u8 type;
+ u8 flags;
+ u8 reserved[18];
+ u8 start_clu[4];
+ u8 size[8];
+};
+
+/* MS-DOS EXFAT up-case table directory entry (32 bytes) */
+struct case_dentry_t {
+ u8 type;
+ u8 reserved1[3];
+ u8 checksum[4];
+ u8 reserved2[12];
+ u8 start_clu[4];
+ u8 size[8];
+};
+
+/* MS-DOS EXFAT volume label directory entry (32 bytes) */
+struct volm_dentry_t {
+ u8 type;
+ u8 label_len;
+ u8 unicode_0_10[22];
+ u8 reserved[8];
+};
+
+/* unused entry hint information */
+struct uentry_t {
+ u32 dir;
+ s32 entry;
+ struct chain_t clu;
+};
+
+/* DOS name structure */
+struct dos_name_t {
+ u8 name[DOS_NAME_LENGTH];
+ u8 name_case;
+};
+
+/* unicode name structure */
+struct uni_name_t {
+ u16 name[MAX_NAME_LENGTH];
+ u16 name_hash;
+ u8 name_len;
+};
+
+struct buf_cache_t {
+ struct buf_cache_t *next;
+ struct buf_cache_t *prev;
+ struct buf_cache_t *hash_next;
+ struct buf_cache_t *hash_prev;
+ s32 drv;
+ sector_t sec;
+ u32 flag;
+ struct buffer_head *buf_bh;
+};
+
+struct fs_func {
+ s32 (*alloc_cluster)(struct super_block *sb, s32 num_alloc,
+ struct chain_t *p_chain);
+ void (*free_cluster)(struct super_block *sb, struct chain_t *p_chain,
+ s32 do_relse);
+ s32 (*count_used_clusters)(struct super_block *sb);
+
+ s32 (*init_dir_entry)(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, u32 type, u32 start_clu, u64 size);
+ s32 (*init_ext_entry)(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 num_entries,
+ struct uni_name_t *p_uniname,
+ struct dos_name_t *p_dosname);
+ s32 (*find_dir_entry)(struct super_block *sb, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, s32 num_entries,
+ struct dos_name_t *p_dosname, u32 type);
+ void (*delete_dir_entry)(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ s32 offset, s32 num_entries);
+ void (*get_uni_name_from_ext_entry)(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ u16 *uniname);
+ s32 (*count_ext_entries)(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ struct dentry_t *p_entry);
+ s32 (*calc_num_entries)(struct uni_name_t *p_uniname);
+
+ u32 (*get_entry_type)(struct dentry_t *p_entry);
+ void (*set_entry_type)(struct dentry_t *p_entry, u32 type);
+ u32 (*get_entry_attr)(struct dentry_t *p_entry);
+ void (*set_entry_attr)(struct dentry_t *p_entry, u32 attr);
+ u8 (*get_entry_flag)(struct dentry_t *p_entry);
+ void (*set_entry_flag)(struct dentry_t *p_entry, u8 flag);
+ u32 (*get_entry_clu0)(struct dentry_t *p_entry);
+ void (*set_entry_clu0)(struct dentry_t *p_entry, u32 clu0);
+ u64 (*get_entry_size)(struct dentry_t *p_entry);
+ void (*set_entry_size)(struct dentry_t *p_entry, u64 size);
+ void (*get_entry_time)(struct dentry_t *p_entry,
+ struct timestamp_t *tp, u8 mode);
+ void (*set_entry_time)(struct dentry_t *p_entry,
+ struct timestamp_t *tp, u8 mode);
+};
+
+struct fs_info_t {
+ u32 drv; /* drive ID */
+ u32 vol_type; /* volume FAT type */
+ u32 vol_id; /* volume serial number */
+
+ u64 num_sectors; /* num of sectors in volume */
+ u32 num_clusters; /* num of clusters in volume */
+ u32 cluster_size; /* cluster size in bytes */
+ u32 cluster_size_bits;
+ u32 sectors_per_clu; /* cluster size in sectors */
+ u32 sectors_per_clu_bits;
+
+ u32 PBR_sector; /* PBR sector */
+ u32 FAT1_start_sector; /* FAT1 start sector */
+ u32 FAT2_start_sector; /* FAT2 start sector */
+ u32 root_start_sector; /* root dir start sector */
+ u32 data_start_sector; /* data area start sector */
+ u32 num_FAT_sectors; /* num of FAT sectors */
+
+ u32 root_dir; /* root dir cluster */
+ u32 dentries_in_root; /* num of dentries in root dir */
+ u32 dentries_per_clu; /* num of dentries per cluster */
+
+ u32 vol_flag; /* volume dirty flag */
+ struct buffer_head *pbr_bh; /* PBR sector */
+
+ u32 map_clu; /* allocation bitmap start cluster */
+ u32 map_sectors; /* num of allocation bitmap sectors */
+ struct buffer_head **vol_amap; /* allocation bitmap */
+
+ u16 **vol_utbl; /* upcase table */
+
+ u32 clu_srch_ptr; /* cluster search pointer */
+ u32 used_clusters; /* number of used clusters */
+ struct uentry_t hint_uentry; /* unused entry hint information */
+
+ u32 dev_ejected; /* block device operation error flag */
+
+ struct fs_func *fs_func;
+ struct semaphore v_sem;
+
+ /* FAT cache */
+ struct buf_cache_t FAT_cache_array[FAT_CACHE_SIZE];
+ struct buf_cache_t FAT_cache_lru_list;
+ struct buf_cache_t FAT_cache_hash_list[FAT_CACHE_HASH_SIZE];
+
+ /* buf cache */
+ struct buf_cache_t buf_cache_array[BUF_CACHE_SIZE];
+ struct buf_cache_t buf_cache_lru_list;
+ struct buf_cache_t buf_cache_hash_list[BUF_CACHE_HASH_SIZE];
+};
+
+#define ES_2_ENTRIES 2
+#define ES_3_ENTRIES 3
+#define ES_ALL_ENTRIES 0
+
+struct entry_set_cache_t {
+ /* sector number that contains file_entry */
+ sector_t sector;
+
+ /* byte offset in the sector */
+ s32 offset;
+
+ /*
+ * flag in stream entry.
+ * 01 for cluster chain,
+ * 03 for contig. clusteres.
+ */
+ s32 alloc_flag;
+
+ u32 num_entries;
+
+ /* __buf should be the last member */
+ void *__buf;
+};
+
+#define EXFAT_ERRORS_CONT 1 /* ignore error and continue */
+#define EXFAT_ERRORS_PANIC 2 /* panic on error */
+#define EXFAT_ERRORS_RO 3 /* remount r/o on error */
+
+/* ioctl command */
+#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32)
+
+struct exfat_mount_options {
+ kuid_t fs_uid;
+ kgid_t fs_gid;
+ unsigned short fs_fmask;
+ unsigned short fs_dmask;
+
+ /* permission for setting the [am]time */
+ unsigned short allow_utime;
+
+ /* codepage for shortname conversions */
+ unsigned short codepage;
+
+ /* charset for filename input/display */
+ char *iocharset;
+
+ unsigned char casesensitive;
+
+ /* on error: continue, panic, remount-ro */
+ unsigned char errors;
+#ifdef CONFIG_EXFAT_DISCARD
+ /* flag on if -o dicard specified and device support discard() */
+ unsigned char discard;
+#endif /* CONFIG_EXFAT_DISCARD */
+};
+
+#define EXFAT_HASH_BITS 8
+#define EXFAT_HASH_SIZE BIT(EXFAT_HASH_BITS)
+
+/*
+ * EXFAT file system in-core superblock data
+ */
+struct bd_info_t {
+ s32 sector_size; /* in bytes */
+ s32 sector_size_bits;
+ s32 sector_size_mask;
+
+ /* total number of sectors in this block device */
+ s32 num_sectors;
+
+ /* opened or not */
+ bool opened;
+};
+
+struct exfat_sb_info {
+ struct fs_info_t fs_info;
+ struct bd_info_t bd_info;
+
+ struct exfat_mount_options options;
+
+ int s_dirt;
+ struct mutex s_lock;
+ struct nls_table *nls_disk; /* Codepage used on disk */
+ struct nls_table *nls_io; /* Charset used for input and display */
+
+ struct inode *fat_inode;
+
+ spinlock_t inode_hash_lock;
+ struct hlist_head inode_hashtable[EXFAT_HASH_SIZE];
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ long debug_flags;
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+};
+
+/*
+ * EXFAT file system inode data in memory
+ */
+struct exfat_inode_info {
+ struct file_id_t fid;
+ char *target;
+ /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */
+ loff_t mmu_private; /* physically allocated size */
+ loff_t i_pos; /* on-disk position of directory entry or 0 */
+ struct hlist_node i_hash_fat; /* hash by i_location */
+ struct rw_semaphore truncate_lock;
+ struct inode vfs_inode;
+ struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */
+};
+
+#define EXFAT_SB(sb) ((struct exfat_sb_info *)((sb)->s_fs_info))
+
+static inline struct exfat_inode_info *EXFAT_I(struct inode *inode)
+{
+ return container_of(inode, struct exfat_inode_info, vfs_inode);
+}
+
+/* NLS management function */
+u16 nls_upper(struct super_block *sb, u16 a);
+int nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b);
+int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b);
+void nls_uniname_to_dosname(struct super_block *sb,
+ struct dos_name_t *p_dosname,
+ struct uni_name_t *p_uniname, bool *p_lossy);
+void nls_dosname_to_uniname(struct super_block *sb,
+ struct uni_name_t *p_uniname,
+ struct dos_name_t *p_dosname);
+void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring,
+ struct uni_name_t *p_uniname);
+void nls_cstring_to_uniname(struct super_block *sb,
+ struct uni_name_t *p_uniname, u8 *p_cstring,
+ bool *p_lossy);
+
+/* buffer cache management */
+void buf_init(struct super_block *sb);
+void buf_shutdown(struct super_block *sb);
+int FAT_read(struct super_block *sb, u32 loc, u32 *content);
+s32 FAT_write(struct super_block *sb, u32 loc, u32 content);
+u8 *FAT_getblk(struct super_block *sb, sector_t sec);
+void FAT_modify(struct super_block *sb, sector_t sec);
+void FAT_release_all(struct super_block *sb);
+void FAT_sync(struct super_block *sb);
+u8 *buf_getblk(struct super_block *sb, sector_t sec);
+void buf_modify(struct super_block *sb, sector_t sec);
+void buf_lock(struct super_block *sb, sector_t sec);
+void buf_unlock(struct super_block *sb, sector_t sec);
+void buf_release(struct super_block *sb, sector_t sec);
+void buf_release_all(struct super_block *sb);
+void buf_sync(struct super_block *sb);
+
+/* fs management functions */
+void fs_set_vol_flags(struct super_block *sb, u32 new_flag);
+void fs_error(struct super_block *sb);
+
+/* cluster management functions */
+s32 clear_cluster(struct super_block *sb, u32 clu);
+s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc,
+ struct chain_t *p_chain);
+s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc,
+ struct chain_t *p_chain);
+void fat_free_cluster(struct super_block *sb, struct chain_t *p_chain,
+ s32 do_relse);
+void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain,
+ s32 do_relse);
+u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain);
+s32 count_num_clusters(struct super_block *sb, struct chain_t *dir);
+s32 fat_count_used_clusters(struct super_block *sb);
+s32 exfat_count_used_clusters(struct super_block *sb);
+void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len);
+
+/* allocation bitmap management functions */
+s32 load_alloc_bitmap(struct super_block *sb);
+void free_alloc_bitmap(struct super_block *sb);
+s32 set_alloc_bitmap(struct super_block *sb, u32 clu);
+s32 clr_alloc_bitmap(struct super_block *sb, u32 clu);
+u32 test_alloc_bitmap(struct super_block *sb, u32 clu);
+void sync_alloc_bitmap(struct super_block *sb);
+
+/* upcase table management functions */
+s32 load_upcase_table(struct super_block *sb);
+void free_upcase_table(struct super_block *sb);
+
+/* dir entry management functions */
+u32 fat_get_entry_type(struct dentry_t *p_entry);
+u32 exfat_get_entry_type(struct dentry_t *p_entry);
+void fat_set_entry_type(struct dentry_t *p_entry, u32 type);
+void exfat_set_entry_type(struct dentry_t *p_entry, u32 type);
+u32 fat_get_entry_attr(struct dentry_t *p_entry);
+u32 exfat_get_entry_attr(struct dentry_t *p_entry);
+void fat_set_entry_attr(struct dentry_t *p_entry, u32 attr);
+void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr);
+u8 fat_get_entry_flag(struct dentry_t *p_entry);
+u8 exfat_get_entry_flag(struct dentry_t *p_entry);
+void fat_set_entry_flag(struct dentry_t *p_entry, u8 flag);
+void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flag);
+u32 fat_get_entry_clu0(struct dentry_t *p_entry);
+u32 exfat_get_entry_clu0(struct dentry_t *p_entry);
+void fat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu);
+void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu);
+u64 fat_get_entry_size(struct dentry_t *p_entry);
+u64 exfat_get_entry_size(struct dentry_t *p_entry);
+void fat_set_entry_size(struct dentry_t *p_entry, u64 size);
+void exfat_set_entry_size(struct dentry_t *p_entry, u64 size);
+struct timestamp_t *tm_current(struct timestamp_t *tm);
+void fat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
+ u8 mode);
+void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
+ u8 mode);
+void fat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
+ u8 mode);
+void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
+ u8 mode);
+s32 fat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, s32 entry,
+ u32 type, u32 start_clu, u64 size);
+s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, u32 type, u32 start_clu, u64 size);
+s32 fat_init_ext_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 num_entries,
+ struct uni_name_t *p_uniname,
+ struct dos_name_t *p_dosname);
+s32 exfat_init_ext_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 num_entries,
+ struct uni_name_t *p_uniname,
+ struct dos_name_t *p_dosname);
+void init_dos_entry(struct dos_dentry_t *ep, u32 type, u32 start_clu);
+void init_ext_entry(struct ext_dentry_t *ep, s32 order, u8 chksum,
+ u16 *uniname);
+void init_file_entry(struct file_dentry_t *ep, u32 type);
+void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu,
+ u64 size);
+void init_name_entry(struct name_dentry_t *ep, u16 *uniname);
+void fat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 order, s32 num_entries);
+void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 order, s32 num_entries);
+
+s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry,
+ sector_t *sector, s32 *offset);
+struct dentry_t *get_entry_with_sector(struct super_block *sb, sector_t sector,
+ s32 offset);
+struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, sector_t *sector);
+struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ u32 type,
+ struct dentry_t **file_ep);
+void release_entry_set(struct entry_set_cache_t *es);
+s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es);
+s32 write_partial_entries_in_entry_set(struct super_block *sb,
+ struct entry_set_cache_t *es,
+ struct dentry_t *ep, u32 count);
+s32 search_deleted_or_unused_entry(struct super_block *sb,
+ struct chain_t *p_dir, s32 num_entries);
+s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir,
+ s32 num_entries);
+s32 fat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, s32 num_entries,
+ struct dos_name_t *p_dosname, u32 type);
+s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, s32 num_entries,
+ struct dos_name_t *p_dosname, u32 type);
+s32 fat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, struct dentry_t *p_entry);
+s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, struct dentry_t *p_entry);
+s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir,
+ u32 type);
+void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry);
+void update_dir_checksum_with_entry_set(struct super_block *sb,
+ struct entry_set_cache_t *es);
+bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir);
+
+/* name conversion functions */
+s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, s32 *entries,
+ struct dos_name_t *p_dosname);
+void get_uni_name_from_dos_entry(struct super_block *sb,
+ struct dos_dentry_t *ep,
+ struct uni_name_t *p_uniname, u8 mode);
+void fat_get_uni_name_from_ext_entry(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ u16 *uniname);
+void exfat_get_uni_name_from_ext_entry(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ u16 *uniname);
+s32 extract_uni_name_from_ext_entry(struct ext_dentry_t *ep,
+ u16 *uniname, s32 order);
+s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep,
+ u16 *uniname, s32 order);
+s32 fat_generate_dos_name(struct super_block *sb, struct chain_t *p_dir,
+ struct dos_name_t *p_dosname);
+void fat_attach_count_to_dos_name(u8 *dosname, s32 count);
+s32 fat_calc_num_entries(struct uni_name_t *p_uniname);
+s32 exfat_calc_num_entries(struct uni_name_t *p_uniname);
+u8 calc_checksum_1byte(void *data, s32 len, u8 chksum);
+u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type);
+u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type);
+
+/* name resolution functions */
+s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname);
+s32 resolve_name(u8 *name, u8 **arg);
+
+/* file operation functions */
+s32 fat16_mount(struct super_block *sb, struct pbr_sector_t *p_pbr);
+s32 fat32_mount(struct super_block *sb, struct pbr_sector_t *p_pbr);
+s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr);
+s32 create_dir(struct inode *inode, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, struct file_id_t *fid);
+s32 create_file(struct inode *inode, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid);
+void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry);
+s32 rename_file(struct inode *inode, struct chain_t *p_dir, s32 old_entry,
+ struct uni_name_t *p_uniname, struct file_id_t *fid);
+s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry,
+ struct chain_t *p_newdir, struct uni_name_t *p_uniname,
+ struct file_id_t *fid);
+
+/* sector read/write functions */
+int sector_read(struct super_block *sb, sector_t sec,
+ struct buffer_head **bh, bool read);
+int sector_write(struct super_block *sb, sector_t sec,
+ struct buffer_head *bh, bool sync);
+int multi_sector_read(struct super_block *sb, sector_t sec,
+ struct buffer_head **bh, s32 num_secs, bool read);
+int multi_sector_write(struct super_block *sb, sector_t sec,
+ struct buffer_head *bh, s32 num_secs, bool sync);
+
+void bdev_open(struct super_block *sb);
+void bdev_close(struct super_block *sb);
+int bdev_read(struct super_block *sb, sector_t secno,
+ struct buffer_head **bh, u32 num_secs, bool read);
+int bdev_write(struct super_block *sb, sector_t secno,
+ struct buffer_head *bh, u32 num_secs, bool sync);
+int bdev_sync(struct super_block *sb);
+
+extern const u8 uni_upcase[];
+#endif /* _EXFAT_H */
diff --git a/drivers/staging/exfat/exfat_blkdev.c b/drivers/staging/exfat/exfat_blkdev.c
new file mode 100644
index 000000000000..f086c75e7076
--- /dev/null
+++ b/drivers/staging/exfat/exfat_blkdev.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/fs.h>
+#include "exfat.h"
+
+void bdev_open(struct super_block *sb)
+{
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ if (p_bd->opened)
+ return;
+
+ p_bd->sector_size = bdev_logical_block_size(sb->s_bdev);
+ p_bd->sector_size_bits = ilog2(p_bd->sector_size);
+ p_bd->sector_size_mask = p_bd->sector_size - 1;
+ p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >>
+ p_bd->sector_size_bits;
+ p_bd->opened = true;
+}
+
+void bdev_close(struct super_block *sb)
+{
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ p_bd->opened = false;
+}
+
+int bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh,
+ u32 num_secs, bool read)
+{
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ long flags = sbi->debug_flags;
+
+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
+ return FFS_MEDIAERR;
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+ if (!p_bd->opened)
+ return FFS_MEDIAERR;
+
+ if (*bh)
+ __brelse(*bh);
+
+ if (read)
+ *bh = __bread(sb->s_bdev, secno,
+ num_secs << p_bd->sector_size_bits);
+ else
+ *bh = __getblk(sb->s_bdev, secno,
+ num_secs << p_bd->sector_size_bits);
+
+ if (*bh)
+ return 0;
+
+ WARN(!p_fs->dev_ejected,
+ "[EXFAT] No bh, device seems wrong or to be ejected.\n");
+
+ return FFS_MEDIAERR;
+}
+
+int bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh,
+ u32 num_secs, bool sync)
+{
+ s32 count;
+ struct buffer_head *bh2;
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ long flags = sbi->debug_flags;
+
+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
+ return FFS_MEDIAERR;
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+ if (!p_bd->opened)
+ return FFS_MEDIAERR;
+
+ if (secno == bh->b_blocknr) {
+ lock_buffer(bh);
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+ unlock_buffer(bh);
+ if (sync && (sync_dirty_buffer(bh) != 0))
+ return FFS_MEDIAERR;
+ } else {
+ count = num_secs << p_bd->sector_size_bits;
+
+ bh2 = __getblk(sb->s_bdev, secno, count);
+ if (!bh2)
+ goto no_bh;
+
+ lock_buffer(bh2);
+ memcpy(bh2->b_data, bh->b_data, count);
+ set_buffer_uptodate(bh2);
+ mark_buffer_dirty(bh2);
+ unlock_buffer(bh2);
+ if (sync && (sync_dirty_buffer(bh2) != 0)) {
+ __brelse(bh2);
+ goto no_bh;
+ }
+ __brelse(bh2);
+ }
+
+ return 0;
+
+no_bh:
+ WARN(!p_fs->dev_ejected,
+ "[EXFAT] No bh, device seems wrong or to be ejected.\n");
+
+ return FFS_MEDIAERR;
+}
+
+int bdev_sync(struct super_block *sb)
+{
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ long flags = sbi->debug_flags;
+
+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
+ return FFS_MEDIAERR;
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+ if (!p_bd->opened)
+ return FFS_MEDIAERR;
+
+ return sync_blockdev(sb->s_bdev);
+}
diff --git a/drivers/staging/exfat/exfat_cache.c b/drivers/staging/exfat/exfat_cache.c
new file mode 100644
index 000000000000..1565ce65d39f
--- /dev/null
+++ b/drivers/staging/exfat/exfat_cache.c
@@ -0,0 +1,724 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include "exfat.h"
+
+#define LOCKBIT 0x01
+#define DIRTYBIT 0x02
+
+/* Local variables */
+static DEFINE_SEMAPHORE(f_sem);
+static DEFINE_SEMAPHORE(b_sem);
+
+static struct buf_cache_t *FAT_cache_find(struct super_block *sb, sector_t sec)
+{
+ s32 off;
+ struct buf_cache_t *bp, *hp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ off = (sec +
+ (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1);
+
+ hp = &p_fs->FAT_cache_hash_list[off];
+ for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) {
+ if ((bp->drv == p_fs->drv) && (bp->sec == sec)) {
+ WARN(!bp->buf_bh,
+ "[EXFAT] FAT_cache has no bh. It will make system panic.\n");
+
+ touch_buffer(bp->buf_bh);
+ return bp;
+ }
+ }
+ return NULL;
+}
+
+static void push_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list)
+{
+ bp->next = list->next;
+ bp->prev = list;
+ list->next->prev = bp;
+ list->next = bp;
+}
+
+static void push_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list)
+{
+ bp->prev = list->prev;
+ bp->next = list;
+ list->prev->next = bp;
+ list->prev = bp;
+}
+
+static void move_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list)
+{
+ bp->prev->next = bp->next;
+ bp->next->prev = bp->prev;
+ push_to_mru(bp, list);
+}
+
+static void move_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list)
+{
+ bp->prev->next = bp->next;
+ bp->next->prev = bp->prev;
+ push_to_lru(bp, list);
+}
+
+static struct buf_cache_t *FAT_cache_get(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ bp = p_fs->FAT_cache_lru_list.prev;
+
+ move_to_mru(bp, &p_fs->FAT_cache_lru_list);
+ return bp;
+}
+
+static void FAT_cache_insert_hash(struct super_block *sb,
+ struct buf_cache_t *bp)
+{
+ s32 off;
+ struct buf_cache_t *hp;
+ struct fs_info_t *p_fs;
+
+ p_fs = &(EXFAT_SB(sb)->fs_info);
+ off = (bp->sec +
+ (bp->sec >> p_fs->sectors_per_clu_bits)) &
+ (FAT_CACHE_HASH_SIZE - 1);
+
+ hp = &p_fs->FAT_cache_hash_list[off];
+ bp->hash_next = hp->hash_next;
+ bp->hash_prev = hp;
+ hp->hash_next->hash_prev = bp;
+ hp->hash_next = bp;
+}
+
+static void FAT_cache_remove_hash(struct buf_cache_t *bp)
+{
+ (bp->hash_prev)->hash_next = bp->hash_next;
+ (bp->hash_next)->hash_prev = bp->hash_prev;
+}
+
+static void buf_cache_insert_hash(struct super_block *sb,
+ struct buf_cache_t *bp)
+{
+ s32 off;
+ struct buf_cache_t *hp;
+ struct fs_info_t *p_fs;
+
+ p_fs = &(EXFAT_SB(sb)->fs_info);
+ off = (bp->sec +
+ (bp->sec >> p_fs->sectors_per_clu_bits)) &
+ (BUF_CACHE_HASH_SIZE - 1);
+
+ hp = &p_fs->buf_cache_hash_list[off];
+ bp->hash_next = hp->hash_next;
+ bp->hash_prev = hp;
+ hp->hash_next->hash_prev = bp;
+ hp->hash_next = bp;
+}
+
+static void buf_cache_remove_hash(struct buf_cache_t *bp)
+{
+ (bp->hash_prev)->hash_next = bp->hash_next;
+ (bp->hash_next)->hash_prev = bp->hash_prev;
+}
+
+void buf_init(struct super_block *sb)
+{
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ int i;
+
+ /* LRU list */
+ p_fs->FAT_cache_lru_list.next = &p_fs->FAT_cache_lru_list;
+ p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list;
+
+ for (i = 0; i < FAT_CACHE_SIZE; i++) {
+ p_fs->FAT_cache_array[i].drv = -1;
+ p_fs->FAT_cache_array[i].sec = ~0;
+ p_fs->FAT_cache_array[i].flag = 0;
+ p_fs->FAT_cache_array[i].buf_bh = NULL;
+ p_fs->FAT_cache_array[i].prev = NULL;
+ p_fs->FAT_cache_array[i].next = NULL;
+ push_to_mru(&p_fs->FAT_cache_array[i],
+ &p_fs->FAT_cache_lru_list);
+ }
+
+ p_fs->buf_cache_lru_list.next = &p_fs->buf_cache_lru_list;
+ p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list;
+
+ for (i = 0; i < BUF_CACHE_SIZE; i++) {
+ p_fs->buf_cache_array[i].drv = -1;
+ p_fs->buf_cache_array[i].sec = ~0;
+ p_fs->buf_cache_array[i].flag = 0;
+ p_fs->buf_cache_array[i].buf_bh = NULL;
+ p_fs->buf_cache_array[i].prev = NULL;
+ p_fs->buf_cache_array[i].next = NULL;
+ push_to_mru(&p_fs->buf_cache_array[i],
+ &p_fs->buf_cache_lru_list);
+ }
+
+ /* HASH list */
+ for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) {
+ p_fs->FAT_cache_hash_list[i].drv = -1;
+ p_fs->FAT_cache_hash_list[i].sec = ~0;
+ p_fs->FAT_cache_hash_list[i].hash_next =
+ &p_fs->FAT_cache_hash_list[i];
+ p_fs->FAT_cache_hash_list[i].hash_prev =
+ &p_fs->FAT_cache_hash_list[i];
+ }
+
+ for (i = 0; i < FAT_CACHE_SIZE; i++)
+ FAT_cache_insert_hash(sb, &p_fs->FAT_cache_array[i]);
+
+ for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) {
+ p_fs->buf_cache_hash_list[i].drv = -1;
+ p_fs->buf_cache_hash_list[i].sec = ~0;
+ p_fs->buf_cache_hash_list[i].hash_next =
+ &p_fs->buf_cache_hash_list[i];
+ p_fs->buf_cache_hash_list[i].hash_prev =
+ &p_fs->buf_cache_hash_list[i];
+ }
+
+ for (i = 0; i < BUF_CACHE_SIZE; i++)
+ buf_cache_insert_hash(sb, &p_fs->buf_cache_array[i]);
+}
+
+void buf_shutdown(struct super_block *sb)
+{
+}
+
+static int __FAT_read(struct super_block *sb, u32 loc, u32 *content)
+{
+ s32 off;
+ u32 _content;
+ sector_t sec;
+ u8 *fat_sector, *fat_entry;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ if (p_fs->vol_type == FAT12) {
+ sec = p_fs->FAT1_start_sector +
+ ((loc + (loc >> 1)) >> p_bd->sector_size_bits);
+ off = (loc + (loc >> 1)) & p_bd->sector_size_mask;
+
+ if (off == (p_bd->sector_size - 1)) {
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ _content = (u32)fat_sector[off];
+
+ fat_sector = FAT_getblk(sb, ++sec);
+ if (!fat_sector)
+ return -1;
+
+ _content |= (u32)fat_sector[0] << 8;
+ } else {
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ fat_entry = &fat_sector[off];
+ _content = GET16(fat_entry);
+ }
+
+ if (loc & 1)
+ _content >>= 4;
+
+ _content &= 0x00000FFF;
+
+ if (_content >= CLUSTER_16(0x0FF8)) {
+ *content = CLUSTER_32(~0);
+ return 0;
+ }
+ *content = CLUSTER_32(_content);
+ return 0;
+ } else if (p_fs->vol_type == FAT16) {
+ sec = p_fs->FAT1_start_sector +
+ (loc >> (p_bd->sector_size_bits - 1));
+ off = (loc << 1) & p_bd->sector_size_mask;
+
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ fat_entry = &fat_sector[off];
+
+ _content = GET16_A(fat_entry);
+
+ _content &= 0x0000FFFF;
+
+ if (_content >= CLUSTER_16(0xFFF8)) {
+ *content = CLUSTER_32(~0);
+ return 0;
+ }
+ *content = CLUSTER_32(_content);
+ return 0;
+ } else if (p_fs->vol_type == FAT32) {
+ sec = p_fs->FAT1_start_sector +
+ (loc >> (p_bd->sector_size_bits - 2));
+ off = (loc << 2) & p_bd->sector_size_mask;
+
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ fat_entry = &fat_sector[off];
+
+ _content = GET32_A(fat_entry);
+
+ _content &= 0x0FFFFFFF;
+
+ if (_content >= CLUSTER_32(0x0FFFFFF8)) {
+ *content = CLUSTER_32(~0);
+ return 0;
+ }
+ *content = CLUSTER_32(_content);
+ return 0;
+ } else if (p_fs->vol_type == EXFAT) {
+ sec = p_fs->FAT1_start_sector +
+ (loc >> (p_bd->sector_size_bits - 2));
+ off = (loc << 2) & p_bd->sector_size_mask;
+
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ fat_entry = &fat_sector[off];
+ _content = GET32_A(fat_entry);
+
+ if (_content >= CLUSTER_32(0xFFFFFFF8)) {
+ *content = CLUSTER_32(~0);
+ return 0;
+ }
+ *content = CLUSTER_32(_content);
+ return 0;
+ }
+
+ /* Unknown volume type, throw in the towel and go home */
+ *content = CLUSTER_32(~0);
+ return 0;
+}
+
+/* in : sb, loc
+ * out: content
+ * returns 0 on success
+ * -1 on error
+ */
+int FAT_read(struct super_block *sb, u32 loc, u32 *content)
+{
+ s32 ret;
+
+ down(&f_sem);
+ ret = __FAT_read(sb, loc, content);
+ up(&f_sem);
+
+ return ret;
+}
+
+static s32 __FAT_write(struct super_block *sb, u32 loc, u32 content)
+{
+ s32 off;
+ sector_t sec;
+ u8 *fat_sector, *fat_entry;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ if (p_fs->vol_type == FAT12) {
+ content &= 0x00000FFF;
+
+ sec = p_fs->FAT1_start_sector +
+ ((loc + (loc >> 1)) >> p_bd->sector_size_bits);
+ off = (loc + (loc >> 1)) & p_bd->sector_size_mask;
+
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ if (loc & 1) { /* odd */
+ content <<= 4;
+
+ if (off == (p_bd->sector_size - 1)) {
+ fat_sector[off] = (u8)(content |
+ (fat_sector[off] &
+ 0x0F));
+ FAT_modify(sb, sec);
+
+ fat_sector = FAT_getblk(sb, ++sec);
+ if (!fat_sector)
+ return -1;
+
+ fat_sector[0] = (u8)(content >> 8);
+ } else {
+ fat_entry = &fat_sector[off];
+ content |= GET16(fat_entry) & 0x000F;
+
+ SET16(fat_entry, content);
+ }
+ } else { /* even */
+ fat_sector[off] = (u8)(content);
+
+ if (off == (p_bd->sector_size - 1)) {
+ fat_sector[off] = (u8)(content);
+ FAT_modify(sb, sec);
+
+ fat_sector = FAT_getblk(sb, ++sec);
+ if (!fat_sector)
+ return -1;
+ fat_sector[0] = (u8)((fat_sector[0] & 0xF0) |
+ (content >> 8));
+ } else {
+ fat_entry = &fat_sector[off];
+ content |= GET16(fat_entry) & 0xF000;
+
+ SET16(fat_entry, content);
+ }
+ }
+ }
+
+ else if (p_fs->vol_type == FAT16) {
+ content &= 0x0000FFFF;
+
+ sec = p_fs->FAT1_start_sector + (loc >>
+ (p_bd->sector_size_bits - 1));
+ off = (loc << 1) & p_bd->sector_size_mask;
+
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ fat_entry = &fat_sector[off];
+
+ SET16_A(fat_entry, content);
+ } else if (p_fs->vol_type == FAT32) {
+ content &= 0x0FFFFFFF;
+
+ sec = p_fs->FAT1_start_sector + (loc >>
+ (p_bd->sector_size_bits - 2));
+ off = (loc << 2) & p_bd->sector_size_mask;
+
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ fat_entry = &fat_sector[off];
+
+ content |= GET32_A(fat_entry) & 0xF0000000;
+
+ SET32_A(fat_entry, content);
+ } else { /* p_fs->vol_type == EXFAT */
+ sec = p_fs->FAT1_start_sector + (loc >>
+ (p_bd->sector_size_bits - 2));
+ off = (loc << 2) & p_bd->sector_size_mask;
+
+ fat_sector = FAT_getblk(sb, sec);
+ if (!fat_sector)
+ return -1;
+
+ fat_entry = &fat_sector[off];
+
+ SET32_A(fat_entry, content);
+ }
+
+ FAT_modify(sb, sec);
+ return 0;
+}
+
+int FAT_write(struct super_block *sb, u32 loc, u32 content)
+{
+ s32 ret;
+
+ down(&f_sem);
+ ret = __FAT_write(sb, loc, content);
+ up(&f_sem);
+
+ return ret;
+}
+
+u8 *FAT_getblk(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ bp = FAT_cache_find(sb, sec);
+ if (bp) {
+ move_to_mru(bp, &p_fs->FAT_cache_lru_list);
+ return bp->buf_bh->b_data;
+ }
+
+ bp = FAT_cache_get(sb, sec);
+
+ FAT_cache_remove_hash(bp);
+
+ bp->drv = p_fs->drv;
+ bp->sec = sec;
+ bp->flag = 0;
+
+ FAT_cache_insert_hash(sb, bp);
+
+ if (sector_read(sb, sec, &bp->buf_bh, 1) != FFS_SUCCESS) {
+ FAT_cache_remove_hash(bp);
+ bp->drv = -1;
+ bp->sec = ~0;
+ bp->flag = 0;
+ bp->buf_bh = NULL;
+
+ move_to_lru(bp, &p_fs->FAT_cache_lru_list);
+ return NULL;
+ }
+
+ return bp->buf_bh->b_data;
+}
+
+void FAT_modify(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+
+ bp = FAT_cache_find(sb, sec);
+ if (bp)
+ sector_write(sb, sec, bp->buf_bh, 0);
+}
+
+void FAT_release_all(struct super_block *sb)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ down(&f_sem);
+
+ bp = p_fs->FAT_cache_lru_list.next;
+ while (bp != &p_fs->FAT_cache_lru_list) {
+ if (bp->drv == p_fs->drv) {
+ bp->drv = -1;
+ bp->sec = ~0;
+ bp->flag = 0;
+
+ if (bp->buf_bh) {
+ __brelse(bp->buf_bh);
+ bp->buf_bh = NULL;
+ }
+ }
+ bp = bp->next;
+ }
+
+ up(&f_sem);
+}
+
+void FAT_sync(struct super_block *sb)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ down(&f_sem);
+
+ bp = p_fs->FAT_cache_lru_list.next;
+ while (bp != &p_fs->FAT_cache_lru_list) {
+ if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) {
+ sync_dirty_buffer(bp->buf_bh);
+ bp->flag &= ~(DIRTYBIT);
+ }
+ bp = bp->next;
+ }
+
+ up(&f_sem);
+}
+
+static struct buf_cache_t *buf_cache_find(struct super_block *sb, sector_t sec)
+{
+ s32 off;
+ struct buf_cache_t *bp, *hp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ off = (sec + (sec >> p_fs->sectors_per_clu_bits)) &
+ (BUF_CACHE_HASH_SIZE - 1);
+
+ hp = &p_fs->buf_cache_hash_list[off];
+ for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) {
+ if ((bp->drv == p_fs->drv) && (bp->sec == sec)) {
+ touch_buffer(bp->buf_bh);
+ return bp;
+ }
+ }
+ return NULL;
+}
+
+static struct buf_cache_t *buf_cache_get(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ bp = p_fs->buf_cache_lru_list.prev;
+ while (bp->flag & LOCKBIT)
+ bp = bp->prev;
+
+ move_to_mru(bp, &p_fs->buf_cache_lru_list);
+ return bp;
+}
+
+static u8 *__buf_getblk(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ bp = buf_cache_find(sb, sec);
+ if (bp) {
+ move_to_mru(bp, &p_fs->buf_cache_lru_list);
+ return bp->buf_bh->b_data;
+ }
+
+ bp = buf_cache_get(sb, sec);
+
+ buf_cache_remove_hash(bp);
+
+ bp->drv = p_fs->drv;
+ bp->sec = sec;
+ bp->flag = 0;
+
+ buf_cache_insert_hash(sb, bp);
+
+ if (sector_read(sb, sec, &bp->buf_bh, 1) != FFS_SUCCESS) {
+ buf_cache_remove_hash(bp);
+ bp->drv = -1;
+ bp->sec = ~0;
+ bp->flag = 0;
+ bp->buf_bh = NULL;
+
+ move_to_lru(bp, &p_fs->buf_cache_lru_list);
+ return NULL;
+ }
+
+ return bp->buf_bh->b_data;
+}
+
+u8 *buf_getblk(struct super_block *sb, sector_t sec)
+{
+ u8 *buf;
+
+ down(&b_sem);
+ buf = __buf_getblk(sb, sec);
+ up(&b_sem);
+
+ return buf;
+}
+
+void buf_modify(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+
+ down(&b_sem);
+
+ bp = buf_cache_find(sb, sec);
+ if (likely(bp))
+ sector_write(sb, sec, bp->buf_bh, 0);
+
+ WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n",
+ (unsigned long long)sec);
+
+ up(&b_sem);
+}
+
+void buf_lock(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+
+ down(&b_sem);
+
+ bp = buf_cache_find(sb, sec);
+ if (likely(bp))
+ bp->flag |= LOCKBIT;
+
+ WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n",
+ (unsigned long long)sec);
+
+ up(&b_sem);
+}
+
+void buf_unlock(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+
+ down(&b_sem);
+
+ bp = buf_cache_find(sb, sec);
+ if (likely(bp))
+ bp->flag &= ~(LOCKBIT);
+
+ WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n",
+ (unsigned long long)sec);
+
+ up(&b_sem);
+}
+
+void buf_release(struct super_block *sb, sector_t sec)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ down(&b_sem);
+
+ bp = buf_cache_find(sb, sec);
+ if (likely(bp)) {
+ bp->drv = -1;
+ bp->sec = ~0;
+ bp->flag = 0;
+
+ if (bp->buf_bh) {
+ __brelse(bp->buf_bh);
+ bp->buf_bh = NULL;
+ }
+
+ move_to_lru(bp, &p_fs->buf_cache_lru_list);
+ }
+
+ up(&b_sem);
+}
+
+void buf_release_all(struct super_block *sb)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ down(&b_sem);
+
+ bp = p_fs->buf_cache_lru_list.next;
+ while (bp != &p_fs->buf_cache_lru_list) {
+ if (bp->drv == p_fs->drv) {
+ bp->drv = -1;
+ bp->sec = ~0;
+ bp->flag = 0;
+
+ if (bp->buf_bh) {
+ __brelse(bp->buf_bh);
+ bp->buf_bh = NULL;
+ }
+ }
+ bp = bp->next;
+ }
+
+ up(&b_sem);
+}
+
+void buf_sync(struct super_block *sb)
+{
+ struct buf_cache_t *bp;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ down(&b_sem);
+
+ bp = p_fs->buf_cache_lru_list.next;
+ while (bp != &p_fs->buf_cache_lru_list) {
+ if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) {
+ sync_dirty_buffer(bp->buf_bh);
+ bp->flag &= ~(DIRTYBIT);
+ }
+ bp = bp->next;
+ }
+
+ up(&b_sem);
+}
diff --git a/drivers/staging/exfat/exfat_core.c b/drivers/staging/exfat/exfat_core.c
new file mode 100644
index 000000000000..b3e9cf725cf5
--- /dev/null
+++ b/drivers/staging/exfat/exfat_core.c
@@ -0,0 +1,3701 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/types.h>
+#include <linux/buffer_head.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include "exfat.h"
+
+static void __set_sb_dirty(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ sbi->s_dirt = 1;
+}
+
+static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE];
+
+static char *reserved_names[] = {
+ "AUX ", "CON ", "NUL ", "PRN ",
+ "COM1 ", "COM2 ", "COM3 ", "COM4 ",
+ "COM5 ", "COM6 ", "COM7 ", "COM8 ", "COM9 ",
+ "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ",
+ "LPT5 ", "LPT6 ", "LPT7 ", "LPT8 ", "LPT9 ",
+ NULL
+};
+
+static u8 free_bit[] = {
+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 0 ~ 19 */
+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /* 20 ~ 39 */
+ 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 40 ~ 59 */
+ 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 ~ 79 */
+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /* 80 ~ 99 */
+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */
+ 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */
+ 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */
+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */
+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */
+ 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */
+ 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */
+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 240 ~ 254 */
+};
+
+static u8 used_bit[] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /* 0 ~ 19 */
+ 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /* 20 ~ 39 */
+ 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /* 40 ~ 59 */
+ 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 60 ~ 79 */
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /* 80 ~ 99 */
+ 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */
+ 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */
+ 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */
+ 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */
+ 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */
+ 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /* 240 ~ 255 */
+};
+
+#define BITMAP_LOC(v) ((v) >> 3)
+#define BITMAP_SHIFT(v) ((v) & 0x07)
+
+static inline s32 exfat_bitmap_test(u8 *bitmap, int i)
+{
+ u8 data;
+
+ data = bitmap[BITMAP_LOC(i)];
+ if ((data >> BITMAP_SHIFT(i)) & 0x01)
+ return 1;
+ return 0;
+}
+
+static inline void exfat_bitmap_set(u8 *bitmap, int i)
+{
+ bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i));
+}
+
+static inline void exfat_bitmap_clear(u8 *bitmap, int i)
+{
+ bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i));
+}
+
+/*
+ * File System Management Functions
+ */
+
+void fs_set_vol_flags(struct super_block *sb, u32 new_flag)
+{
+ struct pbr_sector_t *p_pbr;
+ struct bpbex_t *p_bpb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (p_fs->vol_flag == new_flag)
+ return;
+
+ p_fs->vol_flag = new_flag;
+
+ if (p_fs->vol_type == EXFAT) {
+ if (!p_fs->pbr_bh) {
+ if (sector_read(sb, p_fs->PBR_sector,
+ &p_fs->pbr_bh, 1) != FFS_SUCCESS)
+ return;
+ }
+
+ p_pbr = (struct pbr_sector_t *)p_fs->pbr_bh->b_data;
+ p_bpb = (struct bpbex_t *)p_pbr->bpb;
+ SET16(p_bpb->vol_flags, (u16)new_flag);
+
+ /* XXX duyoung
+ * what can we do here? (cuz fs_set_vol_flags() is void)
+ */
+ if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh)))
+ sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1);
+ else
+ sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0);
+ }
+}
+
+void fs_error(struct super_block *sb)
+{
+ struct exfat_mount_options *opts = &EXFAT_SB(sb)->options;
+
+ if (opts->errors == EXFAT_ERRORS_PANIC) {
+ panic("[EXFAT] Filesystem panic from previous error\n");
+ } else if ((opts->errors == EXFAT_ERRORS_RO) && !sb_rdonly(sb)) {
+ sb->s_flags |= SB_RDONLY;
+ pr_err("[EXFAT] Filesystem has been set read-only\n");
+ }
+}
+
+/*
+ * Cluster Management Functions
+ */
+
+s32 clear_cluster(struct super_block *sb, u32 clu)
+{
+ sector_t s, n;
+ s32 ret = FFS_SUCCESS;
+ struct buffer_head *tmp_bh = NULL;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */
+ s = p_fs->root_start_sector;
+ n = p_fs->data_start_sector;
+ } else {
+ s = START_SECTOR(clu);
+ n = s + p_fs->sectors_per_clu;
+ }
+
+ for (; s < n; s++) {
+ ret = sector_read(sb, s, &tmp_bh, 0);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ memset((char *)tmp_bh->b_data, 0x0, p_bd->sector_size);
+ ret = sector_write(sb, s, tmp_bh, 0);
+ if (ret != FFS_SUCCESS)
+ break;
+ }
+
+ brelse(tmp_bh);
+ return ret;
+}
+
+s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc,
+ struct chain_t *p_chain)
+{
+ int i, num_clusters = 0;
+ u32 new_clu, last_clu = CLUSTER_32(~0), read_clu;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ new_clu = p_chain->dir;
+ if (new_clu == CLUSTER_32(~0))
+ new_clu = p_fs->clu_srch_ptr;
+ else if (new_clu >= p_fs->num_clusters)
+ new_clu = 2;
+
+ __set_sb_dirty(sb);
+
+ p_chain->dir = CLUSTER_32(~0);
+
+ for (i = 2; i < p_fs->num_clusters; i++) {
+ if (FAT_read(sb, new_clu, &read_clu) != 0)
+ return -1;
+
+ if (read_clu == CLUSTER_32(0)) {
+ if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0)
+ return -1;
+ num_clusters++;
+
+ if (p_chain->dir == CLUSTER_32(~0)) {
+ p_chain->dir = new_clu;
+ } else {
+ if (FAT_write(sb, last_clu, new_clu) < 0)
+ return -1;
+ }
+
+ last_clu = new_clu;
+
+ if ((--num_alloc) == 0) {
+ p_fs->clu_srch_ptr = new_clu;
+ if (p_fs->used_clusters != UINT_MAX)
+ p_fs->used_clusters += num_clusters;
+
+ return num_clusters;
+ }
+ }
+ if ((++new_clu) >= p_fs->num_clusters)
+ new_clu = 2;
+ }
+
+ p_fs->clu_srch_ptr = new_clu;
+ if (p_fs->used_clusters != UINT_MAX)
+ p_fs->used_clusters += num_clusters;
+
+ return num_clusters;
+}
+
+s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc,
+ struct chain_t *p_chain)
+{
+ s32 num_clusters = 0;
+ u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0);
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ hint_clu = p_chain->dir;
+ if (hint_clu == CLUSTER_32(~0)) {
+ hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr - 2);
+ if (hint_clu == CLUSTER_32(~0))
+ return 0;
+ } else if (hint_clu >= p_fs->num_clusters) {
+ hint_clu = 2;
+ p_chain->flags = 0x01;
+ }
+
+ __set_sb_dirty(sb);
+
+ p_chain->dir = CLUSTER_32(~0);
+
+ while ((new_clu = test_alloc_bitmap(sb, hint_clu - 2)) != CLUSTER_32(~0)) {
+ if (new_clu != hint_clu) {
+ if (p_chain->flags == 0x03) {
+ exfat_chain_cont_cluster(sb, p_chain->dir,
+ num_clusters);
+ p_chain->flags = 0x01;
+ }
+ }
+
+ if (set_alloc_bitmap(sb, new_clu - 2) != FFS_SUCCESS)
+ return -1;
+
+ num_clusters++;
+
+ if (p_chain->flags == 0x01) {
+ if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0)
+ return -1;
+ }
+
+ if (p_chain->dir == CLUSTER_32(~0)) {
+ p_chain->dir = new_clu;
+ } else {
+ if (p_chain->flags == 0x01) {
+ if (FAT_write(sb, last_clu, new_clu) < 0)
+ return -1;
+ }
+ }
+ last_clu = new_clu;
+
+ if ((--num_alloc) == 0) {
+ p_fs->clu_srch_ptr = hint_clu;
+ if (p_fs->used_clusters != UINT_MAX)
+ p_fs->used_clusters += num_clusters;
+
+ p_chain->size += num_clusters;
+ return num_clusters;
+ }
+
+ hint_clu = new_clu + 1;
+ if (hint_clu >= p_fs->num_clusters) {
+ hint_clu = 2;
+
+ if (p_chain->flags == 0x03) {
+ exfat_chain_cont_cluster(sb, p_chain->dir,
+ num_clusters);
+ p_chain->flags = 0x01;
+ }
+ }
+ }
+
+ p_fs->clu_srch_ptr = hint_clu;
+ if (p_fs->used_clusters != UINT_MAX)
+ p_fs->used_clusters += num_clusters;
+
+ p_chain->size += num_clusters;
+ return num_clusters;
+}
+
+void fat_free_cluster(struct super_block *sb, struct chain_t *p_chain,
+ s32 do_relse)
+{
+ s32 num_clusters = 0;
+ u32 clu, prev;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ int i;
+ sector_t sector;
+
+ if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0)))
+ return;
+ __set_sb_dirty(sb);
+ clu = p_chain->dir;
+
+ if (p_chain->size <= 0)
+ return;
+
+ do {
+ if (p_fs->dev_ejected)
+ break;
+
+ if (do_relse) {
+ sector = START_SECTOR(clu);
+ for (i = 0; i < p_fs->sectors_per_clu; i++)
+ buf_release(sb, sector + i);
+ }
+
+ prev = clu;
+ if (FAT_read(sb, clu, &clu) == -1)
+ break;
+
+ if (FAT_write(sb, prev, CLUSTER_32(0)) < 0)
+ break;
+ num_clusters++;
+
+ } while (clu != CLUSTER_32(~0));
+
+ if (p_fs->used_clusters != UINT_MAX)
+ p_fs->used_clusters -= num_clusters;
+}
+
+void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain,
+ s32 do_relse)
+{
+ s32 num_clusters = 0;
+ u32 clu;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ int i;
+ sector_t sector;
+
+ if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0)))
+ return;
+
+ if (p_chain->size <= 0) {
+ pr_err("[EXFAT] free_cluster : skip free-req clu:%u, because of zero-size truncation\n",
+ p_chain->dir);
+ return;
+ }
+
+ __set_sb_dirty(sb);
+ clu = p_chain->dir;
+
+ if (p_chain->flags == 0x03) {
+ do {
+ if (do_relse) {
+ sector = START_SECTOR(clu);
+ for (i = 0; i < p_fs->sectors_per_clu; i++)
+ buf_release(sb, sector + i);
+ }
+
+ if (clr_alloc_bitmap(sb, clu - 2) != FFS_SUCCESS)
+ break;
+ clu++;
+
+ num_clusters++;
+ } while (num_clusters < p_chain->size);
+ } else {
+ do {
+ if (p_fs->dev_ejected)
+ break;
+
+ if (do_relse) {
+ sector = START_SECTOR(clu);
+ for (i = 0; i < p_fs->sectors_per_clu; i++)
+ buf_release(sb, sector + i);
+ }
+
+ if (clr_alloc_bitmap(sb, clu - 2) != FFS_SUCCESS)
+ break;
+
+ if (FAT_read(sb, clu, &clu) == -1)
+ break;
+ num_clusters++;
+ } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0)));
+ }
+
+ if (p_fs->used_clusters != UINT_MAX)
+ p_fs->used_clusters -= num_clusters;
+}
+
+u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain)
+{
+ u32 clu, next;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ clu = p_chain->dir;
+
+ if (p_chain->flags == 0x03) {
+ clu += p_chain->size - 1;
+ } else {
+ while ((FAT_read(sb, clu, &next) == 0) &&
+ (next != CLUSTER_32(~0))) {
+ if (p_fs->dev_ejected)
+ break;
+ clu = next;
+ }
+ }
+
+ return clu;
+}
+
+s32 count_num_clusters(struct super_block *sb, struct chain_t *p_chain)
+{
+ int i, count = 0;
+ u32 clu;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0)))
+ return 0;
+
+ clu = p_chain->dir;
+
+ if (p_chain->flags == 0x03) {
+ count = p_chain->size;
+ } else {
+ for (i = 2; i < p_fs->num_clusters; i++) {
+ count++;
+ if (FAT_read(sb, clu, &clu) != 0)
+ return 0;
+ if (clu == CLUSTER_32(~0))
+ break;
+ }
+ }
+
+ return count;
+}
+
+s32 fat_count_used_clusters(struct super_block *sb)
+{
+ int i, count = 0;
+ u32 clu;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ for (i = 2; i < p_fs->num_clusters; i++) {
+ if (FAT_read(sb, i, &clu) != 0)
+ break;
+ if (clu != CLUSTER_32(0))
+ count++;
+ }
+
+ return count;
+}
+
+s32 exfat_count_used_clusters(struct super_block *sb)
+{
+ int i, map_i, map_b, count = 0;
+ u8 k;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ map_i = map_b = 0;
+
+ for (i = 2; i < p_fs->num_clusters; i += 8) {
+ k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b);
+ count += used_bit[k];
+
+ if ((++map_b) >= p_bd->sector_size) {
+ map_i++;
+ map_b = 0;
+ }
+ }
+
+ return count;
+}
+
+void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len)
+{
+ if (len == 0)
+ return;
+
+ while (len > 1) {
+ if (FAT_write(sb, chain, chain + 1) < 0)
+ break;
+ chain++;
+ len--;
+ }
+ FAT_write(sb, chain, CLUSTER_32(~0));
+}
+
+/*
+ * Allocation Bitmap Management Functions
+ */
+
+s32 load_alloc_bitmap(struct super_block *sb)
+{
+ int i, j, ret;
+ u32 map_size;
+ u32 type;
+ sector_t sector;
+ struct chain_t clu;
+ struct bmap_dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ clu.dir = p_fs->root_dir;
+ clu.flags = 0x01;
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ if (p_fs->dev_ejected)
+ break;
+
+ for (i = 0; i < p_fs->dentries_per_clu; i++) {
+ ep = (struct bmap_dentry_t *)get_entry_in_dir(sb, &clu,
+ i, NULL);
+ if (!ep)
+ return FFS_MEDIAERR;
+
+ type = p_fs->fs_func->get_entry_type((struct dentry_t *)ep);
+
+ if (type == TYPE_UNUSED)
+ break;
+ if (type != TYPE_BITMAP)
+ continue;
+
+ if (ep->flags == 0x0) {
+ p_fs->map_clu = GET32_A(ep->start_clu);
+ map_size = (u32)GET64_A(ep->size);
+
+ p_fs->map_sectors = ((map_size - 1) >> p_bd->sector_size_bits) + 1;
+
+ p_fs->vol_amap = kmalloc_array(p_fs->map_sectors,
+ sizeof(struct buffer_head *),
+ GFP_KERNEL);
+ if (!p_fs->vol_amap)
+ return FFS_MEMORYERR;
+
+ sector = START_SECTOR(p_fs->map_clu);
+
+ for (j = 0; j < p_fs->map_sectors; j++) {
+ p_fs->vol_amap[j] = NULL;
+ ret = sector_read(sb, sector + j, &(p_fs->vol_amap[j]), 1);
+ if (ret != FFS_SUCCESS) {
+ /* release all buffers and free vol_amap */
+ i = 0;
+ while (i < j)
+ brelse(p_fs->vol_amap[i++]);
+
+ kfree(p_fs->vol_amap);
+ p_fs->vol_amap = NULL;
+ return ret;
+ }
+ }
+
+ p_fs->pbr_bh = NULL;
+ return FFS_SUCCESS;
+ }
+ }
+
+ if (FAT_read(sb, clu.dir, &clu.dir) != 0)
+ return FFS_MEDIAERR;
+ }
+
+ return FFS_FORMATERR;
+}
+
+void free_alloc_bitmap(struct super_block *sb)
+{
+ int i;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ brelse(p_fs->pbr_bh);
+
+ for (i = 0; i < p_fs->map_sectors; i++)
+ __brelse(p_fs->vol_amap[i]);
+
+ kfree(p_fs->vol_amap);
+ p_fs->vol_amap = NULL;
+}
+
+s32 set_alloc_bitmap(struct super_block *sb, u32 clu)
+{
+ int i, b;
+ sector_t sector;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ i = clu >> (p_bd->sector_size_bits + 3);
+ b = clu & ((p_bd->sector_size << 3) - 1);
+
+ sector = START_SECTOR(p_fs->map_clu) + i;
+
+ exfat_bitmap_set((u8 *)p_fs->vol_amap[i]->b_data, b);
+
+ return sector_write(sb, sector, p_fs->vol_amap[i], 0);
+}
+
+s32 clr_alloc_bitmap(struct super_block *sb, u32 clu)
+{
+ int i, b;
+ sector_t sector;
+#ifdef CONFIG_EXFAT_DISCARD
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct exfat_mount_options *opts = &sbi->options;
+ int ret;
+#endif /* CONFIG_EXFAT_DISCARD */
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ i = clu >> (p_bd->sector_size_bits + 3);
+ b = clu & ((p_bd->sector_size << 3) - 1);
+
+ sector = START_SECTOR(p_fs->map_clu) + i;
+
+ exfat_bitmap_clear((u8 *)p_fs->vol_amap[i]->b_data, b);
+
+ return sector_write(sb, sector, p_fs->vol_amap[i], 0);
+
+#ifdef CONFIG_EXFAT_DISCARD
+ if (opts->discard) {
+ ret = sb_issue_discard(sb, START_SECTOR(clu),
+ (1 << p_fs->sectors_per_clu_bits),
+ GFP_NOFS, 0);
+ if (ret == -EOPNOTSUPP) {
+ pr_warn("discard not supported by device, disabling");
+ opts->discard = 0;
+ }
+ }
+#endif /* CONFIG_EXFAT_DISCARD */
+}
+
+u32 test_alloc_bitmap(struct super_block *sb, u32 clu)
+{
+ int i, map_i, map_b;
+ u32 clu_base, clu_free;
+ u8 k, clu_mask;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ clu_base = (clu & ~(0x7)) + 2;
+ clu_mask = (1 << (clu - clu_base + 2)) - 1;
+
+ map_i = clu >> (p_bd->sector_size_bits + 3);
+ map_b = (clu >> 3) & p_bd->sector_size_mask;
+
+ for (i = 2; i < p_fs->num_clusters; i += 8) {
+ k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b);
+ if (clu_mask > 0) {
+ k |= clu_mask;
+ clu_mask = 0;
+ }
+ if (k < 0xFF) {
+ clu_free = clu_base + free_bit[k];
+ if (clu_free < p_fs->num_clusters)
+ return clu_free;
+ }
+ clu_base += 8;
+
+ if (((++map_b) >= p_bd->sector_size) ||
+ (clu_base >= p_fs->num_clusters)) {
+ if ((++map_i) >= p_fs->map_sectors) {
+ clu_base = 2;
+ map_i = 0;
+ }
+ map_b = 0;
+ }
+ }
+
+ return CLUSTER_32(~0);
+}
+
+void sync_alloc_bitmap(struct super_block *sb)
+{
+ int i;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (!p_fs->vol_amap)
+ return;
+
+ for (i = 0; i < p_fs->map_sectors; i++)
+ sync_dirty_buffer(p_fs->vol_amap[i]);
+}
+
+/*
+ * Upcase table Management Functions
+ */
+static s32 __load_upcase_table(struct super_block *sb, sector_t sector,
+ u32 num_sectors, u32 utbl_checksum)
+{
+ int i, ret = FFS_ERROR;
+ u32 j;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct buffer_head *tmp_bh = NULL;
+ sector_t end_sector = num_sectors + sector;
+
+ bool skip = false;
+ u32 index = 0;
+ u16 uni = 0;
+ u16 **upcase_table;
+
+ u32 checksum = 0;
+
+ upcase_table = p_fs->vol_utbl = kmalloc(UTBL_COL_COUNT * sizeof(u16 *),
+ GFP_KERNEL);
+ if (!upcase_table)
+ return FFS_MEMORYERR;
+ memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *));
+
+ while (sector < end_sector) {
+ ret = sector_read(sb, sector, &tmp_bh, 1);
+ if (ret != FFS_SUCCESS) {
+ pr_debug("sector read (0x%llX)fail\n",
+ (unsigned long long)sector);
+ goto error;
+ }
+ sector++;
+
+ for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) {
+ uni = GET16(((u8 *)tmp_bh->b_data) + i);
+
+ checksum = ((checksum & 1) ? 0x80000000 : 0) +
+ (checksum >> 1) + *(((u8 *)tmp_bh->b_data) +
+ i);
+ checksum = ((checksum & 1) ? 0x80000000 : 0) +
+ (checksum >> 1) + *(((u8 *)tmp_bh->b_data) +
+ (i + 1));
+
+ if (skip) {
+ pr_debug("skip from 0x%X ", index);
+ index += uni;
+ pr_debug("to 0x%X (amount of 0x%X)\n",
+ index, uni);
+ skip = false;
+ } else if (uni == index) {
+ index++;
+ } else if (uni == 0xFFFF) {
+ skip = true;
+ } else { /* uni != index , uni != 0xFFFF */
+ u16 col_index = get_col_index(index);
+
+ if (!upcase_table[col_index]) {
+ pr_debug("alloc = 0x%X\n", col_index);
+ upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT,
+ sizeof(u16), GFP_KERNEL);
+ if (!upcase_table[col_index]) {
+ ret = FFS_MEMORYERR;
+ goto error;
+ }
+
+ for (j = 0; j < UTBL_ROW_COUNT; j++)
+ upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
+ }
+
+ upcase_table[col_index][get_row_index(index)] = uni;
+ index++;
+ }
+ }
+ }
+ if (index >= 0xFFFF && utbl_checksum == checksum) {
+ if (tmp_bh)
+ brelse(tmp_bh);
+ return FFS_SUCCESS;
+ }
+ ret = FFS_ERROR;
+error:
+ if (tmp_bh)
+ brelse(tmp_bh);
+ free_upcase_table(sb);
+ return ret;
+}
+
+static s32 __load_default_upcase_table(struct super_block *sb)
+{
+ int i, ret = FFS_ERROR;
+ u32 j;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ bool skip = false;
+ u32 index = 0;
+ u16 uni = 0;
+ u16 **upcase_table;
+
+ upcase_table = p_fs->vol_utbl = kmalloc(UTBL_COL_COUNT * sizeof(u16 *),
+ GFP_KERNEL);
+ if (!upcase_table)
+ return FFS_MEMORYERR;
+ memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *));
+
+ for (i = 0; index <= 0xFFFF && i < NUM_UPCASE * 2; i += 2) {
+ uni = GET16(uni_upcase + i);
+ if (skip) {
+ pr_debug("skip from 0x%X ", index);
+ index += uni;
+ pr_debug("to 0x%X (amount of 0x%X)\n", index, uni);
+ skip = false;
+ } else if (uni == index) {
+ index++;
+ } else if (uni == 0xFFFF) {
+ skip = true;
+ } else { /* uni != index , uni != 0xFFFF */
+ u16 col_index = get_col_index(index);
+
+ if (!upcase_table[col_index]) {
+ pr_debug("alloc = 0x%X\n", col_index);
+ upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT,
+ sizeof(u16),
+ GFP_KERNEL);
+ if (!upcase_table[col_index]) {
+ ret = FFS_MEMORYERR;
+ goto error;
+ }
+
+ for (j = 0; j < UTBL_ROW_COUNT; j++)
+ upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
+ }
+
+ upcase_table[col_index][get_row_index(index)] = uni;
+ index++;
+ }
+ }
+
+ if (index >= 0xFFFF)
+ return FFS_SUCCESS;
+
+error:
+ /* FATAL error: default upcase table has error */
+ free_upcase_table(sb);
+ return ret;
+}
+
+s32 load_upcase_table(struct super_block *sb)
+{
+ int i;
+ u32 tbl_clu, tbl_size;
+ sector_t sector;
+ u32 type, num_sectors;
+ struct chain_t clu;
+ struct case_dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ clu.dir = p_fs->root_dir;
+ clu.flags = 0x01;
+
+ if (p_fs->dev_ejected)
+ return FFS_MEDIAERR;
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ for (i = 0; i < p_fs->dentries_per_clu; i++) {
+ ep = (struct case_dentry_t *)get_entry_in_dir(sb, &clu,
+ i, NULL);
+ if (!ep)
+ return FFS_MEDIAERR;
+
+ type = p_fs->fs_func->get_entry_type((struct dentry_t *)ep);
+
+ if (type == TYPE_UNUSED)
+ break;
+ if (type != TYPE_UPCASE)
+ continue;
+
+ tbl_clu = GET32_A(ep->start_clu);
+ tbl_size = (u32)GET64_A(ep->size);
+
+ sector = START_SECTOR(tbl_clu);
+ num_sectors = ((tbl_size - 1) >> p_bd->sector_size_bits) + 1;
+ if (__load_upcase_table(sb, sector, num_sectors,
+ GET32_A(ep->checksum)) != FFS_SUCCESS)
+ break;
+ return FFS_SUCCESS;
+ }
+ if (FAT_read(sb, clu.dir, &clu.dir) != 0)
+ return FFS_MEDIAERR;
+ }
+ /* load default upcase table */
+ return __load_default_upcase_table(sb);
+}
+
+void free_upcase_table(struct super_block *sb)
+{
+ u32 i;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ u16 **upcase_table;
+
+ upcase_table = p_fs->vol_utbl;
+ for (i = 0; i < UTBL_COL_COUNT; i++)
+ kfree(upcase_table[i]);
+
+ kfree(p_fs->vol_utbl);
+ p_fs->vol_utbl = NULL;
+}
+
+/*
+ * Directory Entry Management Functions
+ */
+
+u32 fat_get_entry_type(struct dentry_t *p_entry)
+{
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ if (*(ep->name) == 0x0)
+ return TYPE_UNUSED;
+
+ else if (*(ep->name) == 0xE5)
+ return TYPE_DELETED;
+
+ else if (ep->attr == ATTR_EXTEND)
+ return TYPE_EXTEND;
+
+ else if ((ep->attr & (ATTR_SUBDIR | ATTR_VOLUME)) == ATTR_VOLUME)
+ return TYPE_VOLUME;
+
+ else if ((ep->attr & (ATTR_SUBDIR | ATTR_VOLUME)) == ATTR_SUBDIR)
+ return TYPE_DIR;
+
+ return TYPE_FILE;
+}
+
+u32 exfat_get_entry_type(struct dentry_t *p_entry)
+{
+ struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
+
+ if (ep->type == 0x0) {
+ return TYPE_UNUSED;
+ } else if (ep->type < 0x80) {
+ return TYPE_DELETED;
+ } else if (ep->type == 0x80) {
+ return TYPE_INVALID;
+ } else if (ep->type < 0xA0) {
+ if (ep->type == 0x81) {
+ return TYPE_BITMAP;
+ } else if (ep->type == 0x82) {
+ return TYPE_UPCASE;
+ } else if (ep->type == 0x83) {
+ return TYPE_VOLUME;
+ } else if (ep->type == 0x85) {
+ if (GET16_A(ep->attr) & ATTR_SUBDIR)
+ return TYPE_DIR;
+ else
+ return TYPE_FILE;
+ }
+ return TYPE_CRITICAL_PRI;
+ } else if (ep->type < 0xC0) {
+ if (ep->type == 0xA0)
+ return TYPE_GUID;
+ else if (ep->type == 0xA1)
+ return TYPE_PADDING;
+ else if (ep->type == 0xA2)
+ return TYPE_ACLTAB;
+ return TYPE_BENIGN_PRI;
+ } else if (ep->type < 0xE0) {
+ if (ep->type == 0xC0)
+ return TYPE_STREAM;
+ else if (ep->type == 0xC1)
+ return TYPE_EXTEND;
+ else if (ep->type == 0xC2)
+ return TYPE_ACL;
+ return TYPE_CRITICAL_SEC;
+ }
+
+ return TYPE_BENIGN_SEC;
+}
+
+void fat_set_entry_type(struct dentry_t *p_entry, u32 type)
+{
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ if (type == TYPE_UNUSED)
+ *(ep->name) = 0x0;
+
+ else if (type == TYPE_DELETED)
+ *(ep->name) = 0xE5;
+
+ else if (type == TYPE_EXTEND)
+ ep->attr = ATTR_EXTEND;
+
+ else if (type == TYPE_DIR)
+ ep->attr = ATTR_SUBDIR;
+
+ else if (type == TYPE_FILE)
+ ep->attr = ATTR_ARCHIVE;
+
+ else if (type == TYPE_SYMLINK)
+ ep->attr = ATTR_ARCHIVE | ATTR_SYMLINK;
+}
+
+void exfat_set_entry_type(struct dentry_t *p_entry, u32 type)
+{
+ struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
+
+ if (type == TYPE_UNUSED) {
+ ep->type = 0x0;
+ } else if (type == TYPE_DELETED) {
+ ep->type &= ~0x80;
+ } else if (type == TYPE_STREAM) {
+ ep->type = 0xC0;
+ } else if (type == TYPE_EXTEND) {
+ ep->type = 0xC1;
+ } else if (type == TYPE_BITMAP) {
+ ep->type = 0x81;
+ } else if (type == TYPE_UPCASE) {
+ ep->type = 0x82;
+ } else if (type == TYPE_VOLUME) {
+ ep->type = 0x83;
+ } else if (type == TYPE_DIR) {
+ ep->type = 0x85;
+ SET16_A(ep->attr, ATTR_SUBDIR);
+ } else if (type == TYPE_FILE) {
+ ep->type = 0x85;
+ SET16_A(ep->attr, ATTR_ARCHIVE);
+ } else if (type == TYPE_SYMLINK) {
+ ep->type = 0x85;
+ SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK);
+ }
+}
+
+u32 fat_get_entry_attr(struct dentry_t *p_entry)
+{
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ return (u32)ep->attr;
+}
+
+u32 exfat_get_entry_attr(struct dentry_t *p_entry)
+{
+ struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
+
+ return (u32)GET16_A(ep->attr);
+}
+
+void fat_set_entry_attr(struct dentry_t *p_entry, u32 attr)
+{
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ ep->attr = (u8)attr;
+}
+
+void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr)
+{
+ struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
+
+ SET16_A(ep->attr, (u16)attr);
+}
+
+u8 fat_get_entry_flag(struct dentry_t *p_entry)
+{
+ return 0x01;
+}
+
+u8 exfat_get_entry_flag(struct dentry_t *p_entry)
+{
+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
+
+ return ep->flags;
+}
+
+void fat_set_entry_flag(struct dentry_t *p_entry, u8 flags)
+{
+}
+
+void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags)
+{
+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
+
+ ep->flags = flags;
+}
+
+u32 fat_get_entry_clu0(struct dentry_t *p_entry)
+{
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ return ((u32)GET16_A(ep->start_clu_hi) << 16) |
+ GET16_A(ep->start_clu_lo);
+}
+
+u32 exfat_get_entry_clu0(struct dentry_t *p_entry)
+{
+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
+
+ return GET32_A(ep->start_clu);
+}
+
+void fat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu)
+{
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu));
+ SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16));
+}
+
+void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu)
+{
+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
+
+ SET32_A(ep->start_clu, start_clu);
+}
+
+u64 fat_get_entry_size(struct dentry_t *p_entry)
+{
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ return (u64)GET32_A(ep->size);
+}
+
+u64 exfat_get_entry_size(struct dentry_t *p_entry)
+{
+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
+
+ return GET64_A(ep->valid_size);
+}
+
+void fat_set_entry_size(struct dentry_t *p_entry, u64 size)
+{
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ SET32_A(ep->size, (u32)size);
+}
+
+void exfat_set_entry_size(struct dentry_t *p_entry, u64 size)
+{
+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
+
+ SET64_A(ep->valid_size, size);
+ SET64_A(ep->size, size);
+}
+
+void fat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
+ u8 mode)
+{
+ u16 t = 0x00, d = 0x21;
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ switch (mode) {
+ case TM_CREATE:
+ t = GET16_A(ep->create_time);
+ d = GET16_A(ep->create_date);
+ break;
+ case TM_MODIFY:
+ t = GET16_A(ep->modify_time);
+ d = GET16_A(ep->modify_date);
+ break;
+ }
+
+ tp->sec = (t & 0x001F) << 1;
+ tp->min = (t >> 5) & 0x003F;
+ tp->hour = (t >> 11);
+ tp->day = (d & 0x001F);
+ tp->mon = (d >> 5) & 0x000F;
+ tp->year = (d >> 9);
+}
+
+void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
+ u8 mode)
+{
+ u16 t = 0x00, d = 0x21;
+ struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
+
+ switch (mode) {
+ case TM_CREATE:
+ t = GET16_A(ep->create_time);
+ d = GET16_A(ep->create_date);
+ break;
+ case TM_MODIFY:
+ t = GET16_A(ep->modify_time);
+ d = GET16_A(ep->modify_date);
+ break;
+ case TM_ACCESS:
+ t = GET16_A(ep->access_time);
+ d = GET16_A(ep->access_date);
+ break;
+ }
+
+ tp->sec = (t & 0x001F) << 1;
+ tp->min = (t >> 5) & 0x003F;
+ tp->hour = (t >> 11);
+ tp->day = (d & 0x001F);
+ tp->mon = (d >> 5) & 0x000F;
+ tp->year = (d >> 9);
+}
+
+void fat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
+ u8 mode)
+{
+ u16 t, d;
+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry;
+
+ t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1);
+ d = (tp->year << 9) | (tp->mon << 5) | tp->day;
+
+ switch (mode) {
+ case TM_CREATE:
+ SET16_A(ep->create_time, t);
+ SET16_A(ep->create_date, d);
+ break;
+ case TM_MODIFY:
+ SET16_A(ep->modify_time, t);
+ SET16_A(ep->modify_date, d);
+ break;
+ }
+}
+
+void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
+ u8 mode)
+{
+ u16 t, d;
+ struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
+
+ t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1);
+ d = (tp->year << 9) | (tp->mon << 5) | tp->day;
+
+ switch (mode) {
+ case TM_CREATE:
+ SET16_A(ep->create_time, t);
+ SET16_A(ep->create_date, d);
+ break;
+ case TM_MODIFY:
+ SET16_A(ep->modify_time, t);
+ SET16_A(ep->modify_date, d);
+ break;
+ case TM_ACCESS:
+ SET16_A(ep->access_time, t);
+ SET16_A(ep->access_date, d);
+ break;
+ }
+}
+
+s32 fat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, s32 entry,
+ u32 type, u32 start_clu, u64 size)
+{
+ sector_t sector;
+ struct dos_dentry_t *dos_ep;
+
+ dos_ep = (struct dos_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
+ &sector);
+ if (!dos_ep)
+ return FFS_MEDIAERR;
+
+ init_dos_entry(dos_ep, type, start_clu);
+ buf_modify(sb, sector);
+
+ return FFS_SUCCESS;
+}
+
+s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, u32 type, u32 start_clu, u64 size)
+{
+ sector_t sector;
+ u8 flags;
+ struct file_dentry_t *file_ep;
+ struct strm_dentry_t *strm_ep;
+
+ flags = (type == TYPE_FILE) ? 0x01 : 0x03;
+
+ /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */
+ file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
+ &sector);
+ if (!file_ep)
+ return FFS_MEDIAERR;
+
+ strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1,
+ &sector);
+ if (!strm_ep)
+ return FFS_MEDIAERR;
+
+ init_file_entry(file_ep, type);
+ buf_modify(sb, sector);
+
+ init_strm_entry(strm_ep, flags, start_clu, size);
+ buf_modify(sb, sector);
+
+ return FFS_SUCCESS;
+}
+
+static s32 fat_init_ext_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 num_entries,
+ struct uni_name_t *p_uniname,
+ struct dos_name_t *p_dosname)
+{
+ int i;
+ sector_t sector;
+ u8 chksum;
+ u16 *uniname = p_uniname->name;
+ struct dos_dentry_t *dos_ep;
+ struct ext_dentry_t *ext_ep;
+
+ dos_ep = (struct dos_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
+ &sector);
+ if (!dos_ep)
+ return FFS_MEDIAERR;
+
+ dos_ep->lcase = p_dosname->name_case;
+ memcpy(dos_ep->name, p_dosname->name, DOS_NAME_LENGTH);
+ buf_modify(sb, sector);
+
+ if ((--num_entries) > 0) {
+ chksum = calc_checksum_1byte((void *)dos_ep->name,
+ DOS_NAME_LENGTH, 0);
+
+ for (i = 1; i < num_entries; i++) {
+ ext_ep = (struct ext_dentry_t *)get_entry_in_dir(sb,
+ p_dir,
+ entry - i,
+ &sector);
+ if (!ext_ep)
+ return FFS_MEDIAERR;
+
+ init_ext_entry(ext_ep, i, chksum, uniname);
+ buf_modify(sb, sector);
+ uniname += 13;
+ }
+
+ ext_ep = (struct ext_dentry_t *)get_entry_in_dir(sb, p_dir,
+ entry - i,
+ &sector);
+ if (!ext_ep)
+ return FFS_MEDIAERR;
+
+ init_ext_entry(ext_ep, i + 0x40, chksum, uniname);
+ buf_modify(sb, sector);
+ }
+
+ return FFS_SUCCESS;
+}
+
+static s32 exfat_init_ext_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 num_entries,
+ struct uni_name_t *p_uniname,
+ struct dos_name_t *p_dosname)
+{
+ int i;
+ sector_t sector;
+ u16 *uniname = p_uniname->name;
+ struct file_dentry_t *file_ep;
+ struct strm_dentry_t *strm_ep;
+ struct name_dentry_t *name_ep;
+
+ file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
+ &sector);
+ if (!file_ep)
+ return FFS_MEDIAERR;
+
+ file_ep->num_ext = (u8)(num_entries - 1);
+ buf_modify(sb, sector);
+
+ strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1,
+ &sector);
+ if (!strm_ep)
+ return FFS_MEDIAERR;
+
+ strm_ep->name_len = p_uniname->name_len;
+ SET16_A(strm_ep->name_hash, p_uniname->name_hash);
+ buf_modify(sb, sector);
+
+ for (i = 2; i < num_entries; i++) {
+ name_ep = (struct name_dentry_t *)get_entry_in_dir(sb, p_dir,
+ entry + i,
+ &sector);
+ if (!name_ep)
+ return FFS_MEDIAERR;
+
+ init_name_entry(name_ep, uniname);
+ buf_modify(sb, sector);
+ uniname += 15;
+ }
+
+ update_dir_checksum(sb, p_dir, entry);
+
+ return FFS_SUCCESS;
+}
+
+void init_dos_entry(struct dos_dentry_t *ep, u32 type, u32 start_clu)
+{
+ struct timestamp_t tm, *tp;
+
+ fat_set_entry_type((struct dentry_t *)ep, type);
+ SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu));
+ SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16));
+ SET32_A(ep->size, 0);
+
+ tp = tm_current(&tm);
+ fat_set_entry_time((struct dentry_t *)ep, tp, TM_CREATE);
+ fat_set_entry_time((struct dentry_t *)ep, tp, TM_MODIFY);
+ SET16_A(ep->access_date, 0);
+ ep->create_time_ms = 0;
+}
+
+void init_ext_entry(struct ext_dentry_t *ep, s32 order, u8 chksum, u16 *uniname)
+{
+ int i;
+ bool end = false;
+
+ fat_set_entry_type((struct dentry_t *)ep, TYPE_EXTEND);
+ ep->order = (u8)order;
+ ep->sysid = 0;
+ ep->checksum = chksum;
+ SET16_A(ep->start_clu, 0);
+
+ for (i = 0; i < 10; i += 2) {
+ if (!end) {
+ SET16(ep->unicode_0_4 + i, *uniname);
+ if (*uniname == 0x0)
+ end = true;
+ else
+ uniname++;
+ } else {
+ SET16(ep->unicode_0_4 + i, 0xFFFF);
+ }
+ }
+
+ for (i = 0; i < 12; i += 2) {
+ if (!end) {
+ SET16_A(ep->unicode_5_10 + i, *uniname);
+ if (*uniname == 0x0)
+ end = true;
+ else
+ uniname++;
+ } else {
+ SET16_A(ep->unicode_5_10 + i, 0xFFFF);
+ }
+ }
+
+ for (i = 0; i < 4; i += 2) {
+ if (!end) {
+ SET16_A(ep->unicode_11_12 + i, *uniname);
+ if (*uniname == 0x0)
+ end = true;
+ else
+ uniname++;
+ } else {
+ SET16_A(ep->unicode_11_12 + i, 0xFFFF);
+ }
+ }
+}
+
+void init_file_entry(struct file_dentry_t *ep, u32 type)
+{
+ struct timestamp_t tm, *tp;
+
+ exfat_set_entry_type((struct dentry_t *)ep, type);
+
+ tp = tm_current(&tm);
+ exfat_set_entry_time((struct dentry_t *)ep, tp, TM_CREATE);
+ exfat_set_entry_time((struct dentry_t *)ep, tp, TM_MODIFY);
+ exfat_set_entry_time((struct dentry_t *)ep, tp, TM_ACCESS);
+ ep->create_time_ms = 0;
+ ep->modify_time_ms = 0;
+ ep->access_time_ms = 0;
+}
+
+void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu, u64 size)
+{
+ exfat_set_entry_type((struct dentry_t *)ep, TYPE_STREAM);
+ ep->flags = flags;
+ SET32_A(ep->start_clu, start_clu);
+ SET64_A(ep->valid_size, size);
+ SET64_A(ep->size, size);
+}
+
+void init_name_entry(struct name_dentry_t *ep, u16 *uniname)
+{
+ int i;
+
+ exfat_set_entry_type((struct dentry_t *)ep, TYPE_EXTEND);
+ ep->flags = 0x0;
+
+ for (i = 0; i < 30; i++, i++) {
+ SET16_A(ep->unicode_0_14 + i, *uniname);
+ if (*uniname == 0x0)
+ break;
+ uniname++;
+ }
+}
+
+void fat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 order, s32 num_entries)
+{
+ int i;
+ sector_t sector;
+ struct dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ for (i = num_entries - 1; i >= order; i--) {
+ ep = get_entry_in_dir(sb, p_dir, entry - i, &sector);
+ if (!ep)
+ return;
+
+ p_fs->fs_func->set_entry_type(ep, TYPE_DELETED);
+ buf_modify(sb, sector);
+ }
+}
+
+void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, s32 order, s32 num_entries)
+{
+ int i;
+ sector_t sector;
+ struct dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ for (i = order; i < num_entries; i++) {
+ ep = get_entry_in_dir(sb, p_dir, entry + i, &sector);
+ if (!ep)
+ return;
+
+ p_fs->fs_func->set_entry_type(ep, TYPE_DELETED);
+ buf_modify(sb, sector);
+ }
+}
+
+void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry)
+{
+ int i, num_entries;
+ sector_t sector;
+ u16 chksum;
+ struct file_dentry_t *file_ep;
+ struct dentry_t *ep;
+
+ file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
+ &sector);
+ if (!file_ep)
+ return;
+
+ buf_lock(sb, sector);
+
+ num_entries = (s32)file_ep->num_ext + 1;
+ chksum = calc_checksum_2byte((void *)file_ep, DENTRY_SIZE, 0,
+ CS_DIR_ENTRY);
+
+ for (i = 1; i < num_entries; i++) {
+ ep = get_entry_in_dir(sb, p_dir, entry + i, NULL);
+ if (!ep) {
+ buf_unlock(sb, sector);
+ return;
+ }
+
+ chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum,
+ CS_DEFAULT);
+ }
+
+ SET16_A(file_ep->checksum, chksum);
+ buf_modify(sb, sector);
+ buf_unlock(sb, sector);
+}
+
+void update_dir_checksum_with_entry_set(struct super_block *sb,
+ struct entry_set_cache_t *es)
+{
+ struct dentry_t *ep;
+ u16 chksum = 0;
+ s32 chksum_type = CS_DIR_ENTRY, i;
+
+ ep = (struct dentry_t *)&(es->__buf);
+ for (i = 0; i < es->num_entries; i++) {
+ pr_debug("%s ep %p\n", __func__, ep);
+ chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum,
+ chksum_type);
+ ep++;
+ chksum_type = CS_DEFAULT;
+ }
+
+ ep = (struct dentry_t *)&(es->__buf);
+ SET16_A(((struct file_dentry_t *)ep)->checksum, chksum);
+ write_whole_entry_set(sb, es);
+}
+
+static s32 _walk_fat_chain(struct super_block *sb, struct chain_t *p_dir,
+ s32 byte_offset, u32 *clu)
+{
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ s32 clu_offset;
+ u32 cur_clu;
+
+ clu_offset = byte_offset >> p_fs->cluster_size_bits;
+ cur_clu = p_dir->dir;
+
+ if (p_dir->flags == 0x03) {
+ cur_clu += clu_offset;
+ } else {
+ while (clu_offset > 0) {
+ if (FAT_read(sb, cur_clu, &cur_clu) == -1)
+ return FFS_MEDIAERR;
+ clu_offset--;
+ }
+ }
+
+ if (clu)
+ *clu = cur_clu;
+ return FFS_SUCCESS;
+}
+
+s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry,
+ sector_t *sector, s32 *offset)
+{
+ s32 off, ret;
+ u32 clu = 0;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ off = entry << DENTRY_SIZE_BITS;
+
+ if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */
+ *offset = off & p_bd->sector_size_mask;
+ *sector = off >> p_bd->sector_size_bits;
+ *sector += p_fs->root_start_sector;
+ } else {
+ ret = _walk_fat_chain(sb, p_dir, off, &clu);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ /* byte offset in cluster */
+ off &= p_fs->cluster_size - 1;
+
+ /* byte offset in sector */
+ *offset = off & p_bd->sector_size_mask;
+
+ /* sector offset in cluster */
+ *sector = off >> p_bd->sector_size_bits;
+ *sector += START_SECTOR(clu);
+ }
+ return FFS_SUCCESS;
+}
+
+struct dentry_t *get_entry_with_sector(struct super_block *sb, sector_t sector,
+ s32 offset)
+{
+ u8 *buf;
+
+ buf = buf_getblk(sb, sector);
+
+ if (!buf)
+ return NULL;
+
+ return (struct dentry_t *)(buf + offset);
+}
+
+struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, sector_t *sector)
+{
+ s32 off;
+ sector_t sec;
+ u8 *buf;
+
+ if (find_location(sb, p_dir, entry, &sec, &off) != FFS_SUCCESS)
+ return NULL;
+
+ buf = buf_getblk(sb, sec);
+
+ if (!buf)
+ return NULL;
+
+ if (sector)
+ *sector = sec;
+ return (struct dentry_t *)(buf + off);
+}
+
+/* returns a set of dentries for a file or dir.
+ * Note that this is a copy (dump) of dentries so that user should call write_entry_set()
+ * to apply changes made in this entry set to the real device.
+ * in:
+ * sb+p_dir+entry: indicates a file/dir
+ * type: specifies how many dentries should be included.
+ * out:
+ * file_ep: will point the first dentry(= file dentry) on success
+ * return:
+ * pointer of entry set on success,
+ * NULL on failure.
+ */
+
+#define ES_MODE_STARTED 0
+#define ES_MODE_GET_FILE_ENTRY 1
+#define ES_MODE_GET_STRM_ENTRY 2
+#define ES_MODE_GET_NAME_ENTRY 3
+#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4
+struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ u32 type,
+ struct dentry_t **file_ep)
+{
+ s32 off, ret, byte_offset;
+ u32 clu = 0;
+ sector_t sec;
+ u32 entry_type;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct entry_set_cache_t *es = NULL;
+ struct dentry_t *ep, *pos;
+ u8 *buf;
+ u8 num_entries;
+ s32 mode = ES_MODE_STARTED;
+ size_t bufsize;
+
+ pr_debug("%s entered p_dir dir %u flags %x size %d\n",
+ __func__, p_dir->dir, p_dir->flags, p_dir->size);
+
+ byte_offset = entry << DENTRY_SIZE_BITS;
+ ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu);
+ if (ret != FFS_SUCCESS)
+ return NULL;
+
+ /* byte offset in cluster */
+ byte_offset &= p_fs->cluster_size - 1;
+
+ /* byte offset in sector */
+ off = byte_offset & p_bd->sector_size_mask;
+
+ /* sector offset in cluster */
+ sec = byte_offset >> p_bd->sector_size_bits;
+ sec += START_SECTOR(clu);
+
+ buf = buf_getblk(sb, sec);
+ if (!buf)
+ goto err_out;
+
+ ep = (struct dentry_t *)(buf + off);
+ entry_type = p_fs->fs_func->get_entry_type(ep);
+
+ if ((entry_type != TYPE_FILE)
+ && (entry_type != TYPE_DIR))
+ goto err_out;
+
+ if (type == ES_ALL_ENTRIES)
+ num_entries = ((struct file_dentry_t *)ep)->num_ext + 1;
+ else
+ num_entries = type;
+
+ bufsize = offsetof(struct entry_set_cache_t, __buf) + (num_entries) *
+ sizeof(struct dentry_t);
+ pr_debug("%s: trying to kmalloc %zx bytes for %d entries\n", __func__,
+ bufsize, num_entries);
+ es = kmalloc(bufsize, GFP_KERNEL);
+ if (!es)
+ goto err_out;
+
+ es->num_entries = num_entries;
+ es->sector = sec;
+ es->offset = off;
+ es->alloc_flag = p_dir->flags;
+
+ pos = (struct dentry_t *)&es->__buf;
+
+ while (num_entries) {
+ /*
+ * instead of copying whole sector, we will check every entry.
+ * this will provide minimum stablity and consistency.
+ */
+ entry_type = p_fs->fs_func->get_entry_type(ep);
+
+ if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED))
+ goto err_out;
+
+ switch (mode) {
+ case ES_MODE_STARTED:
+ if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR))
+ mode = ES_MODE_GET_FILE_ENTRY;
+ else
+ goto err_out;
+ break;
+ case ES_MODE_GET_FILE_ENTRY:
+ if (entry_type == TYPE_STREAM)
+ mode = ES_MODE_GET_STRM_ENTRY;
+ else
+ goto err_out;
+ break;
+ case ES_MODE_GET_STRM_ENTRY:
+ if (entry_type == TYPE_EXTEND)
+ mode = ES_MODE_GET_NAME_ENTRY;
+ else
+ goto err_out;
+ break;
+ case ES_MODE_GET_NAME_ENTRY:
+ if (entry_type == TYPE_EXTEND)
+ break;
+ else if (entry_type == TYPE_STREAM)
+ goto err_out;
+ else if (entry_type & TYPE_CRITICAL_SEC)
+ mode = ES_MODE_GET_CRITICAL_SEC_ENTRY;
+ else
+ goto err_out;
+ break;
+ case ES_MODE_GET_CRITICAL_SEC_ENTRY:
+ if ((entry_type == TYPE_EXTEND) ||
+ (entry_type == TYPE_STREAM))
+ goto err_out;
+ else if ((entry_type & TYPE_CRITICAL_SEC) !=
+ TYPE_CRITICAL_SEC)
+ goto err_out;
+ break;
+ }
+
+ memcpy(pos, ep, sizeof(struct dentry_t));
+
+ if (--num_entries == 0)
+ break;
+
+ if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) <
+ (off & p_bd->sector_size_mask)) {
+ /* get the next sector */
+ if (IS_LAST_SECTOR_IN_CLUSTER(sec)) {
+ if (es->alloc_flag == 0x03) {
+ clu++;
+ } else {
+ if (FAT_read(sb, clu, &clu) == -1)
+ goto err_out;
+ }
+ sec = START_SECTOR(clu);
+ } else {
+ sec++;
+ }
+ buf = buf_getblk(sb, sec);
+ if (!buf)
+ goto err_out;
+ off = 0;
+ ep = (struct dentry_t *)(buf);
+ } else {
+ ep++;
+ off += DENTRY_SIZE;
+ }
+ pos++;
+ }
+
+ if (file_ep)
+ *file_ep = (struct dentry_t *)&(es->__buf);
+
+ pr_debug("%s exiting es %p sec %llu offset %d flags %d, num_entries %u buf ptr %p\n",
+ __func__, es, (unsigned long long)es->sector, es->offset,
+ es->alloc_flag, es->num_entries, &es->__buf);
+ return es;
+err_out:
+ pr_debug("%s exited NULL (es %p)\n", __func__, es);
+ kfree(es);
+ return NULL;
+}
+
+void release_entry_set(struct entry_set_cache_t *es)
+{
+ pr_debug("%s es=%p\n", __func__, es);
+ kfree(es);
+}
+
+static s32 __write_partial_entries_in_entry_set(struct super_block *sb,
+ struct entry_set_cache_t *es,
+ sector_t sec, s32 off, u32 count)
+{
+ s32 num_entries, buf_off = (off - es->offset);
+ u32 remaining_byte_in_sector, copy_entries;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ u32 clu;
+ u8 *buf, *esbuf = (u8 *)&(es->__buf);
+
+ pr_debug("%s entered es %p sec %llu off %d count %d\n",
+ __func__, es, (unsigned long long)sec, off, count);
+ num_entries = count;
+
+ while (num_entries) {
+ /* white per sector base */
+ remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off;
+ copy_entries = min_t(s32,
+ remaining_byte_in_sector >> DENTRY_SIZE_BITS,
+ num_entries);
+ buf = buf_getblk(sb, sec);
+ if (!buf)
+ goto err_out;
+ pr_debug("es->buf %p buf_off %u\n", esbuf, buf_off);
+ pr_debug("copying %d entries from %p to sector %llu\n",
+ copy_entries, (esbuf + buf_off),
+ (unsigned long long)sec);
+ memcpy(buf + off, esbuf + buf_off,
+ copy_entries << DENTRY_SIZE_BITS);
+ buf_modify(sb, sec);
+ num_entries -= copy_entries;
+
+ if (num_entries) {
+ /* get next sector */
+ if (IS_LAST_SECTOR_IN_CLUSTER(sec)) {
+ clu = GET_CLUSTER_FROM_SECTOR(sec);
+ if (es->alloc_flag == 0x03) {
+ clu++;
+ } else {
+ if (FAT_read(sb, clu, &clu) == -1)
+ goto err_out;
+ }
+ sec = START_SECTOR(clu);
+ } else {
+ sec++;
+ }
+ off = 0;
+ buf_off += copy_entries << DENTRY_SIZE_BITS;
+ }
+ }
+
+ pr_debug("%s exited successfully\n", __func__);
+ return FFS_SUCCESS;
+err_out:
+ pr_debug("%s failed\n", __func__);
+ return FFS_ERROR;
+}
+
+/* write back all entries in entry set */
+s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es)
+{
+ return __write_partial_entries_in_entry_set(sb, es, es->sector,
+ es->offset,
+ es->num_entries);
+}
+
+/* write back some entries in entry set */
+s32 write_partial_entries_in_entry_set(struct super_block *sb,
+ struct entry_set_cache_t *es, struct dentry_t *ep, u32 count)
+{
+ s32 ret, byte_offset, off;
+ u32 clu = 0;
+ sector_t sec;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct chain_t dir;
+
+ /* vaidity check */
+ if (ep + count > ((struct dentry_t *)&(es->__buf)) + es->num_entries)
+ return FFS_ERROR;
+
+ dir.dir = GET_CLUSTER_FROM_SECTOR(es->sector);
+ dir.flags = es->alloc_flag;
+ dir.size = 0xffffffff; /* XXX */
+
+ byte_offset = (es->sector - START_SECTOR(dir.dir)) <<
+ p_bd->sector_size_bits;
+ byte_offset += ((void **)ep - &(es->__buf)) + es->offset;
+
+ ret = _walk_fat_chain(sb, &dir, byte_offset, &clu);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ /* byte offset in cluster */
+ byte_offset &= p_fs->cluster_size - 1;
+
+ /* byte offset in sector */
+ off = byte_offset & p_bd->sector_size_mask;
+
+ /* sector offset in cluster */
+ sec = byte_offset >> p_bd->sector_size_bits;
+ sec += START_SECTOR(clu);
+ return __write_partial_entries_in_entry_set(sb, es, sec, off, count);
+}
+
+/* search EMPTY CONTINUOUS "num_entries" entries */
+s32 search_deleted_or_unused_entry(struct super_block *sb,
+ struct chain_t *p_dir, s32 num_entries)
+{
+ int i, dentry, num_empty = 0;
+ s32 dentries_per_clu;
+ u32 type;
+ struct chain_t clu;
+ struct dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ dentries_per_clu = p_fs->dentries_in_root;
+ else
+ dentries_per_clu = p_fs->dentries_per_clu;
+
+ if (p_fs->hint_uentry.dir == p_dir->dir) {
+ if (p_fs->hint_uentry.entry == -1)
+ return -1;
+
+ clu.dir = p_fs->hint_uentry.clu.dir;
+ clu.size = p_fs->hint_uentry.clu.size;
+ clu.flags = p_fs->hint_uentry.clu.flags;
+
+ dentry = p_fs->hint_uentry.entry;
+ } else {
+ p_fs->hint_uentry.entry = -1;
+
+ clu.dir = p_dir->dir;
+ clu.size = p_dir->size;
+ clu.flags = p_dir->flags;
+
+ dentry = 0;
+ }
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ if (p_fs->dev_ejected)
+ break;
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ i = dentry % dentries_per_clu;
+ else
+ i = dentry & (dentries_per_clu - 1);
+
+ for (; i < dentries_per_clu; i++, dentry++) {
+ ep = get_entry_in_dir(sb, &clu, i, NULL);
+ if (!ep)
+ return -1;
+
+ type = p_fs->fs_func->get_entry_type(ep);
+
+ if (type == TYPE_UNUSED) {
+ num_empty++;
+ if (p_fs->hint_uentry.entry == -1) {
+ p_fs->hint_uentry.dir = p_dir->dir;
+ p_fs->hint_uentry.entry = dentry;
+
+ p_fs->hint_uentry.clu.dir = clu.dir;
+ p_fs->hint_uentry.clu.size = clu.size;
+ p_fs->hint_uentry.clu.flags = clu.flags;
+ }
+ } else if (type == TYPE_DELETED) {
+ num_empty++;
+ } else {
+ num_empty = 0;
+ }
+
+ if (num_empty >= num_entries) {
+ p_fs->hint_uentry.dir = CLUSTER_32(~0);
+ p_fs->hint_uentry.entry = -1;
+
+ if (p_fs->vol_type == EXFAT)
+ return dentry - (num_entries - 1);
+ else
+ return dentry;
+ }
+ }
+
+ if (p_dir->dir == CLUSTER_32(0))
+ break; /* FAT16 root_dir */
+
+ if (clu.flags == 0x03) {
+ if ((--clu.size) > 0)
+ clu.dir++;
+ else
+ clu.dir = CLUSTER_32(~0);
+ } else {
+ if (FAT_read(sb, clu.dir, &clu.dir) != 0)
+ return -1;
+ }
+ }
+
+ return -1;
+}
+
+s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, s32 num_entries)
+{
+ s32 ret, dentry;
+ u32 last_clu;
+ sector_t sector;
+ u64 size = 0;
+ struct chain_t clu;
+ struct dentry_t *ep = NULL;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ return search_deleted_or_unused_entry(sb, p_dir, num_entries);
+
+ while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) {
+ if (p_fs->dev_ejected)
+ break;
+
+ if (p_fs->vol_type == EXFAT) {
+ if (p_dir->dir != p_fs->root_dir)
+ size = i_size_read(inode);
+ }
+
+ last_clu = find_last_cluster(sb, p_dir);
+ clu.dir = last_clu + 1;
+ clu.size = 0;
+ clu.flags = p_dir->flags;
+
+ /* (1) allocate a cluster */
+ ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu);
+ if (ret < 1)
+ return -1;
+
+ if (clear_cluster(sb, clu.dir) != FFS_SUCCESS)
+ return -1;
+
+ /* (2) append to the FAT chain */
+ if (clu.flags != p_dir->flags) {
+ exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size);
+ p_dir->flags = 0x01;
+ p_fs->hint_uentry.clu.flags = 0x01;
+ }
+ if (clu.flags == 0x01)
+ if (FAT_write(sb, last_clu, clu.dir) < 0)
+ return -1;
+
+ if (p_fs->hint_uentry.entry == -1) {
+ p_fs->hint_uentry.dir = p_dir->dir;
+ p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS);
+
+ p_fs->hint_uentry.clu.dir = clu.dir;
+ p_fs->hint_uentry.clu.size = 0;
+ p_fs->hint_uentry.clu.flags = clu.flags;
+ }
+ p_fs->hint_uentry.clu.size++;
+ p_dir->size++;
+
+ /* (3) update the directory entry */
+ if (p_fs->vol_type == EXFAT) {
+ if (p_dir->dir != p_fs->root_dir) {
+ size += p_fs->cluster_size;
+
+ ep = get_entry_in_dir(sb, &fid->dir,
+ fid->entry + 1, &sector);
+ if (!ep)
+ return -1;
+ p_fs->fs_func->set_entry_size(ep, size);
+ p_fs->fs_func->set_entry_flag(ep, p_dir->flags);
+ buf_modify(sb, sector);
+
+ update_dir_checksum(sb, &(fid->dir),
+ fid->entry);
+ }
+ }
+
+ i_size_write(inode, i_size_read(inode) + p_fs->cluster_size);
+ EXFAT_I(inode)->mmu_private += p_fs->cluster_size;
+ EXFAT_I(inode)->fid.size += p_fs->cluster_size;
+ EXFAT_I(inode)->fid.flags = p_dir->flags;
+ inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9);
+ }
+
+ return dentry;
+}
+
+/* return values of fat_find_dir_entry()
+ * >= 0 : return dir entiry position with the name in dir
+ * -1 : (root dir, ".") it is the root dir itself
+ * -2 : entry with the name does not exist
+ */
+s32 fat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, s32 num_entries,
+ struct dos_name_t *p_dosname, u32 type)
+{
+ int i, dentry = 0, len;
+ s32 order = 0;
+ bool is_feasible_entry = true, has_ext_entry = false;
+ s32 dentries_per_clu;
+ u32 entry_type;
+ u16 entry_uniname[14], *uniname = NULL, unichar;
+ struct chain_t clu;
+ struct dentry_t *ep;
+ struct dos_dentry_t *dos_ep;
+ struct ext_dentry_t *ext_ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (p_dir->dir == p_fs->root_dir) {
+ if ((!nls_uniname_cmp(sb, p_uniname->name,
+ (u16 *)UNI_CUR_DIR_NAME)) ||
+ (!nls_uniname_cmp(sb, p_uniname->name,
+ (u16 *)UNI_PAR_DIR_NAME)))
+ return -1; // special case, root directory itself
+ }
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ dentries_per_clu = p_fs->dentries_in_root;
+ else
+ dentries_per_clu = p_fs->dentries_per_clu;
+
+ clu.dir = p_dir->dir;
+ clu.flags = p_dir->flags;
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ if (p_fs->dev_ejected)
+ break;
+
+ for (i = 0; i < dentries_per_clu; i++, dentry++) {
+ ep = get_entry_in_dir(sb, &clu, i, NULL);
+ if (!ep)
+ return -2;
+
+ entry_type = p_fs->fs_func->get_entry_type(ep);
+
+ if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) {
+ if ((type == TYPE_ALL) || (type == entry_type)) {
+ if (is_feasible_entry && has_ext_entry)
+ return dentry;
+
+ dos_ep = (struct dos_dentry_t *)ep;
+ if (!nls_dosname_cmp(sb, p_dosname->name, dos_ep->name))
+ return dentry;
+ }
+ is_feasible_entry = true;
+ has_ext_entry = false;
+ } else if (entry_type == TYPE_EXTEND) {
+ if (is_feasible_entry) {
+ ext_ep = (struct ext_dentry_t *)ep;
+ if (ext_ep->order > 0x40) {
+ order = (s32)(ext_ep->order - 0x40);
+ uniname = p_uniname->name + 13 * (order - 1);
+ } else {
+ order = (s32)ext_ep->order;
+ uniname -= 13;
+ }
+
+ len = extract_uni_name_from_ext_entry(ext_ep, entry_uniname, order);
+
+ unichar = *(uniname + len);
+ *(uniname + len) = 0x0;
+
+ if (nls_uniname_cmp(sb, uniname, entry_uniname))
+ is_feasible_entry = false;
+
+ *(uniname + len) = unichar;
+ }
+ has_ext_entry = true;
+ } else if (entry_type == TYPE_UNUSED) {
+ return -2;
+ }
+ is_feasible_entry = true;
+ has_ext_entry = false;
+ }
+
+ if (p_dir->dir == CLUSTER_32(0))
+ break; /* FAT16 root_dir */
+
+ if (FAT_read(sb, clu.dir, &clu.dir) != 0)
+ return -2;
+ }
+
+ return -2;
+}
+
+/* return values of exfat_find_dir_entry()
+ * >= 0 : return dir entiry position with the name in dir
+ * -1 : (root dir, ".") it is the root dir itself
+ * -2 : entry with the name does not exist
+ */
+s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, s32 num_entries,
+ struct dos_name_t *p_dosname, u32 type)
+{
+ int i = 0, dentry = 0, num_ext_entries = 0, len, step;
+ s32 order = 0;
+ bool is_feasible_entry = false;
+ s32 dentries_per_clu, num_empty = 0;
+ u32 entry_type;
+ u16 entry_uniname[16], *uniname = NULL, unichar;
+ struct chain_t clu;
+ struct dentry_t *ep;
+ struct file_dentry_t *file_ep;
+ struct strm_dentry_t *strm_ep;
+ struct name_dentry_t *name_ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (p_dir->dir == p_fs->root_dir) {
+ if ((!nls_uniname_cmp(sb, p_uniname->name,
+ (u16 *)UNI_CUR_DIR_NAME)) ||
+ (!nls_uniname_cmp(sb, p_uniname->name,
+ (u16 *)UNI_PAR_DIR_NAME)))
+ return -1; // special case, root directory itself
+ }
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ dentries_per_clu = p_fs->dentries_in_root;
+ else
+ dentries_per_clu = p_fs->dentries_per_clu;
+
+ clu.dir = p_dir->dir;
+ clu.size = p_dir->size;
+ clu.flags = p_dir->flags;
+
+ p_fs->hint_uentry.dir = p_dir->dir;
+ p_fs->hint_uentry.entry = -1;
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ if (p_fs->dev_ejected)
+ break;
+
+ while (i < dentries_per_clu) {
+ ep = get_entry_in_dir(sb, &clu, i, NULL);
+ if (!ep)
+ return -2;
+
+ entry_type = p_fs->fs_func->get_entry_type(ep);
+ step = 1;
+
+ if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) {
+ is_feasible_entry = false;
+
+ if (p_fs->hint_uentry.entry == -1) {
+ num_empty++;
+
+ if (num_empty == 1) {
+ p_fs->hint_uentry.clu.dir = clu.dir;
+ p_fs->hint_uentry.clu.size = clu.size;
+ p_fs->hint_uentry.clu.flags = clu.flags;
+ }
+ if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED))
+ p_fs->hint_uentry.entry = dentry - (num_empty - 1);
+ }
+
+ if (entry_type == TYPE_UNUSED)
+ return -2;
+ } else {
+ num_empty = 0;
+
+ if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) {
+ file_ep = (struct file_dentry_t *)ep;
+ if ((type == TYPE_ALL) || (type == entry_type)) {
+ num_ext_entries = file_ep->num_ext;
+ is_feasible_entry = true;
+ } else {
+ is_feasible_entry = false;
+ step = file_ep->num_ext + 1;
+ }
+ } else if (entry_type == TYPE_STREAM) {
+ if (is_feasible_entry) {
+ strm_ep = (struct strm_dentry_t *)ep;
+ if (p_uniname->name_hash == GET16_A(strm_ep->name_hash) &&
+ p_uniname->name_len == strm_ep->name_len) {
+ order = 1;
+ } else {
+ is_feasible_entry = false;
+ step = num_ext_entries;
+ }
+ }
+ } else if (entry_type == TYPE_EXTEND) {
+ if (is_feasible_entry) {
+ name_ep = (struct name_dentry_t *)ep;
+
+ if ((++order) == 2)
+ uniname = p_uniname->name;
+ else
+ uniname += 15;
+
+ len = extract_uni_name_from_name_entry(name_ep,
+ entry_uniname, order);
+
+ unichar = *(uniname + len);
+ *(uniname + len) = 0x0;
+
+ if (nls_uniname_cmp(sb, uniname, entry_uniname)) {
+ is_feasible_entry = false;
+ step = num_ext_entries - order + 1;
+ } else if (order == num_ext_entries) {
+ p_fs->hint_uentry.dir = CLUSTER_32(~0);
+ p_fs->hint_uentry.entry = -1;
+ return dentry - (num_ext_entries);
+ }
+
+ *(uniname + len) = unichar;
+ }
+ } else {
+ is_feasible_entry = false;
+ }
+ }
+
+ i += step;
+ dentry += step;
+ }
+
+ i -= dentries_per_clu;
+
+ if (p_dir->dir == CLUSTER_32(0))
+ break; /* FAT16 root_dir */
+
+ if (clu.flags == 0x03) {
+ if ((--clu.size) > 0)
+ clu.dir++;
+ else
+ clu.dir = CLUSTER_32(~0);
+ } else {
+ if (FAT_read(sb, clu.dir, &clu.dir) != 0)
+ return -2;
+ }
+ }
+
+ return -2;
+}
+
+s32 fat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, struct dentry_t *p_entry)
+{
+ s32 count = 0;
+ u8 chksum;
+ struct dos_dentry_t *dos_ep = (struct dos_dentry_t *)p_entry;
+ struct ext_dentry_t *ext_ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ chksum = calc_checksum_1byte((void *)dos_ep->name, DOS_NAME_LENGTH, 0);
+
+ for (entry--; entry >= 0; entry--) {
+ ext_ep = (struct ext_dentry_t *)get_entry_in_dir(sb, p_dir,
+ entry, NULL);
+ if (!ext_ep)
+ return -1;
+
+ if ((p_fs->fs_func->get_entry_type((struct dentry_t *)ext_ep) ==
+ TYPE_EXTEND) && (ext_ep->checksum == chksum)) {
+ count++;
+ if (ext_ep->order > 0x40)
+ return count;
+ } else {
+ return count;
+ }
+ }
+
+ return count;
+}
+
+s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir,
+ s32 entry, struct dentry_t *p_entry)
+{
+ int i, count = 0;
+ u32 type;
+ struct file_dentry_t *file_ep = (struct file_dentry_t *)p_entry;
+ struct dentry_t *ext_ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) {
+ ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL);
+ if (!ext_ep)
+ return -1;
+
+ type = p_fs->fs_func->get_entry_type(ext_ep);
+ if ((type == TYPE_EXTEND) || (type == TYPE_STREAM))
+ count++;
+ else
+ return count;
+ }
+
+ return count;
+}
+
+s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir,
+ u32 type)
+{
+ int i, count = 0;
+ s32 dentries_per_clu;
+ u32 entry_type;
+ struct chain_t clu;
+ struct dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ dentries_per_clu = p_fs->dentries_in_root;
+ else
+ dentries_per_clu = p_fs->dentries_per_clu;
+
+ clu.dir = p_dir->dir;
+ clu.size = p_dir->size;
+ clu.flags = p_dir->flags;
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ if (p_fs->dev_ejected)
+ break;
+
+ for (i = 0; i < dentries_per_clu; i++) {
+ ep = get_entry_in_dir(sb, &clu, i, NULL);
+ if (!ep)
+ return -1;
+
+ entry_type = p_fs->fs_func->get_entry_type(ep);
+
+ if (entry_type == TYPE_UNUSED)
+ return count;
+ if (!(type & TYPE_CRITICAL_PRI) &&
+ !(type & TYPE_BENIGN_PRI))
+ continue;
+
+ if ((type == TYPE_ALL) || (type == entry_type))
+ count++;
+ }
+
+ if (p_dir->dir == CLUSTER_32(0))
+ break; /* FAT16 root_dir */
+
+ if (clu.flags == 0x03) {
+ if ((--clu.size) > 0)
+ clu.dir++;
+ else
+ clu.dir = CLUSTER_32(~0);
+ } else {
+ if (FAT_read(sb, clu.dir, &clu.dir) != 0)
+ return -1;
+ }
+ }
+
+ return count;
+}
+
+bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir)
+{
+ int i, count = 0;
+ s32 dentries_per_clu;
+ u32 type;
+ struct chain_t clu;
+ struct dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ dentries_per_clu = p_fs->dentries_in_root;
+ else
+ dentries_per_clu = p_fs->dentries_per_clu;
+
+ clu.dir = p_dir->dir;
+ clu.size = p_dir->size;
+ clu.flags = p_dir->flags;
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ if (p_fs->dev_ejected)
+ break;
+
+ for (i = 0; i < dentries_per_clu; i++) {
+ ep = get_entry_in_dir(sb, &clu, i, NULL);
+ if (!ep)
+ break;
+
+ type = p_fs->fs_func->get_entry_type(ep);
+
+ if (type == TYPE_UNUSED)
+ return true;
+ if ((type != TYPE_FILE) && (type != TYPE_DIR))
+ continue;
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ return false;
+
+ if (p_fs->vol_type == EXFAT)
+ return false;
+ if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2))
+ return false;
+ }
+
+ if (p_dir->dir == CLUSTER_32(0))
+ break; /* FAT16 root_dir */
+
+ if (clu.flags == 0x03) {
+ if ((--clu.size) > 0)
+ clu.dir++;
+ else
+ clu.dir = CLUSTER_32(~0);
+ }
+ if (FAT_read(sb, clu.dir, &clu.dir) != 0)
+ break;
+ }
+
+ return true;
+}
+
+/*
+ * Name Conversion Functions
+ */
+
+/* input : dir, uni_name
+ * output : num_of_entry, dos_name(format : aaaaaa~1.bbb)
+ */
+s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, s32 *entries,
+ struct dos_name_t *p_dosname)
+{
+ s32 ret, num_entries;
+ bool lossy = false;
+ char **r;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ num_entries = p_fs->fs_func->calc_num_entries(p_uniname);
+ if (num_entries == 0)
+ return FFS_INVALIDPATH;
+
+ if (p_fs->vol_type != EXFAT) {
+ nls_uniname_to_dosname(sb, p_dosname, p_uniname, &lossy);
+
+ if (lossy) {
+ ret = fat_generate_dos_name(sb, p_dir, p_dosname);
+ if (ret)
+ return ret;
+ } else {
+ for (r = reserved_names; *r; r++) {
+ if (!strncmp((void *)p_dosname->name, *r, 8))
+ return FFS_INVALIDPATH;
+ }
+
+ if (p_dosname->name_case != 0xFF)
+ num_entries = 1;
+ }
+
+ if (num_entries > 1)
+ p_dosname->name_case = 0x0;
+ }
+
+ *entries = num_entries;
+
+ return FFS_SUCCESS;
+}
+
+void get_uni_name_from_dos_entry(struct super_block *sb,
+ struct dos_dentry_t *ep,
+ struct uni_name_t *p_uniname, u8 mode)
+{
+ struct dos_name_t dos_name;
+
+ if (mode == 0x0)
+ dos_name.name_case = 0x0;
+ else
+ dos_name.name_case = ep->lcase;
+
+ memcpy(dos_name.name, ep->name, DOS_NAME_LENGTH);
+ nls_dosname_to_uniname(sb, p_uniname, &dos_name);
+}
+
+void fat_get_uni_name_from_ext_entry(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ u16 *uniname)
+{
+ int i;
+ struct ext_dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ for (entry--, i = 1; entry >= 0; entry--, i++) {
+ ep = (struct ext_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
+ NULL);
+ if (!ep)
+ return;
+
+ if (p_fs->fs_func->get_entry_type((struct dentry_t *)ep) ==
+ TYPE_EXTEND) {
+ extract_uni_name_from_ext_entry(ep, uniname, i);
+ if (ep->order > 0x40)
+ return;
+ } else {
+ return;
+ }
+
+ uniname += 13;
+ }
+}
+
+void exfat_get_uni_name_from_ext_entry(struct super_block *sb,
+ struct chain_t *p_dir, s32 entry,
+ u16 *uniname)
+{
+ int i;
+ struct dentry_t *ep;
+ struct entry_set_cache_t *es;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep);
+ if (!es || es->num_entries < 3) {
+ if (es)
+ release_entry_set(es);
+ return;
+ }
+
+ ep += 2;
+
+ /*
+ * First entry : file entry
+ * Second entry : stream-extension entry
+ * Third entry : first file-name entry
+ * So, the index of first file-name dentry should start from 2.
+ */
+ for (i = 2; i < es->num_entries; i++, ep++) {
+ if (p_fs->fs_func->get_entry_type(ep) == TYPE_EXTEND)
+ extract_uni_name_from_name_entry((struct name_dentry_t *)
+ ep, uniname, i);
+ else
+ goto out;
+ uniname += 15;
+ }
+
+out:
+ release_entry_set(es);
+}
+
+s32 extract_uni_name_from_ext_entry(struct ext_dentry_t *ep, u16 *uniname,
+ s32 order)
+{
+ int i, len = 0;
+
+ for (i = 0; i < 10; i += 2) {
+ *uniname = GET16(ep->unicode_0_4 + i);
+ if (*uniname == 0x0)
+ return len;
+ uniname++;
+ len++;
+ }
+
+ if (order < 20) {
+ for (i = 0; i < 12; i += 2) {
+ *uniname = GET16_A(ep->unicode_5_10 + i);
+ if (*uniname == 0x0)
+ return len;
+ uniname++;
+ len++;
+ }
+ } else {
+ for (i = 0; i < 8; i += 2) {
+ *uniname = GET16_A(ep->unicode_5_10 + i);
+ if (*uniname == 0x0)
+ return len;
+ uniname++;
+ len++;
+ }
+ *uniname = 0x0; /* uniname[MAX_NAME_LENGTH-1] */
+ return len;
+ }
+
+ for (i = 0; i < 4; i += 2) {
+ *uniname = GET16_A(ep->unicode_11_12 + i);
+ if (*uniname == 0x0)
+ return len;
+ uniname++;
+ len++;
+ }
+
+ *uniname = 0x0;
+ return len;
+}
+
+s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep, u16 *uniname,
+ s32 order)
+{
+ int i, len = 0;
+
+ for (i = 0; i < 30; i += 2) {
+ *uniname = GET16_A(ep->unicode_0_14 + i);
+ if (*uniname == 0x0)
+ return len;
+ uniname++;
+ len++;
+ }
+
+ *uniname = 0x0;
+ return len;
+}
+
+s32 fat_generate_dos_name(struct super_block *sb, struct chain_t *p_dir,
+ struct dos_name_t *p_dosname)
+{
+ int i, j, count = 0;
+ bool count_begin = false;
+ s32 dentries_per_clu;
+ u32 type;
+ u8 bmap[128/* 1 ~ 1023 */];
+ struct chain_t clu;
+ struct dos_dentry_t *ep;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ memset(bmap, 0, sizeof(bmap));
+ exfat_bitmap_set(bmap, 0);
+
+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ dentries_per_clu = p_fs->dentries_in_root;
+ else
+ dentries_per_clu = p_fs->dentries_per_clu;
+
+ clu.dir = p_dir->dir;
+ clu.flags = p_dir->flags;
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ if (p_fs->dev_ejected)
+ break;
+
+ for (i = 0; i < dentries_per_clu; i++) {
+ ep = (struct dos_dentry_t *)get_entry_in_dir(sb, &clu,
+ i, NULL);
+ if (!ep)
+ return FFS_MEDIAERR;
+
+ type = p_fs->fs_func->get_entry_type((struct dentry_t *)
+ ep);
+
+ if (type == TYPE_UNUSED)
+ break;
+ if ((type != TYPE_FILE) && (type != TYPE_DIR))
+ continue;
+
+ count = 0;
+ count_begin = false;
+
+ for (j = 0; j < 8; j++) {
+ if (ep->name[j] == ' ')
+ break;
+
+ if (ep->name[j] == '~') {
+ count_begin = true;
+ } else if (count_begin) {
+ if ((ep->name[j] >= '0') &&
+ (ep->name[j] <= '9')) {
+ count = count * 10 +
+ (ep->name[j] - '0');
+ } else {
+ count = 0;
+ count_begin = false;
+ }
+ }
+ }
+
+ if ((count > 0) && (count < 1024))
+ exfat_bitmap_set(bmap, count);
+ }
+
+ if (p_dir->dir == CLUSTER_32(0))
+ break; /* FAT16 root_dir */
+
+ if (FAT_read(sb, clu.dir, &clu.dir) != 0)
+ return FFS_MEDIAERR;
+ }
+
+ count = 0;
+ for (i = 0; i < 128; i++) {
+ if (bmap[i] != 0xFF) {
+ for (j = 0; j < 8; j++) {
+ if (exfat_bitmap_test(&bmap[i], j) == 0) {
+ count = (i << 3) + j;
+ break;
+ }
+ }
+ if (count != 0)
+ break;
+ }
+ }
+
+ if ((count == 0) || (count >= 1024))
+ return FFS_FILEEXIST;
+ fat_attach_count_to_dos_name(p_dosname->name, count);
+
+ /* Now dos_name has DOS~????.EXT */
+ return FFS_SUCCESS;
+}
+
+void fat_attach_count_to_dos_name(u8 *dosname, s32 count)
+{
+ int i, j, length;
+ char str_count[6];
+
+ snprintf(str_count, sizeof(str_count), "~%d", count);
+ length = strlen(str_count);
+
+ i = 0;
+ j = 0;
+ while (j <= (8 - length)) {
+ i = j;
+ if (dosname[j] == ' ')
+ break;
+ if (dosname[j] & 0x80)
+ j += 2;
+ else
+ j++;
+ }
+
+ for (j = 0; j < length; i++, j++)
+ dosname[i] = (u8)str_count[j];
+
+ if (i == 7)
+ dosname[7] = ' ';
+}
+
+s32 fat_calc_num_entries(struct uni_name_t *p_uniname)
+{
+ s32 len;
+
+ len = p_uniname->name_len;
+ if (len == 0)
+ return 0;
+
+ /* 1 dos name entry + extended entries */
+ return (len - 1) / 13 + 2;
+}
+
+s32 exfat_calc_num_entries(struct uni_name_t *p_uniname)
+{
+ s32 len;
+
+ len = p_uniname->name_len;
+ if (len == 0)
+ return 0;
+
+ /* 1 file entry + 1 stream entry + name entries */
+ return (len - 1) / 15 + 3;
+}
+
+u8 calc_checksum_1byte(void *data, s32 len, u8 chksum)
+{
+ int i;
+ u8 *c = (u8 *)data;
+
+ for (i = 0; i < len; i++, c++)
+ chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c;
+
+ return chksum;
+}
+
+u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type)
+{
+ int i;
+ u8 *c = (u8 *)data;
+
+ switch (type) {
+ case CS_DIR_ENTRY:
+ for (i = 0; i < len; i++, c++) {
+ if ((i == 2) || (i == 3))
+ continue;
+ chksum = (((chksum & 1) << 15) |
+ ((chksum & 0xFFFE) >> 1)) + (u16)*c;
+ }
+ break;
+ default
+ :
+ for (i = 0; i < len; i++, c++)
+ chksum = (((chksum & 1) << 15) |
+ ((chksum & 0xFFFE) >> 1)) + (u16)*c;
+ }
+
+ return chksum;
+}
+
+u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type)
+{
+ int i;
+ u8 *c = (u8 *)data;
+
+ switch (type) {
+ case CS_PBR_SECTOR:
+ for (i = 0; i < len; i++, c++) {
+ if ((i == 106) || (i == 107) || (i == 112))
+ continue;
+ chksum = (((chksum & 1) << 31) |
+ ((chksum & 0xFFFFFFFE) >> 1)) + (u32)*c;
+ }
+ break;
+ default
+ :
+ for (i = 0; i < len; i++, c++)
+ chksum = (((chksum & 1) << 31) |
+ ((chksum & 0xFFFFFFFE) >> 1)) + (u32)*c;
+ }
+
+ return chksum;
+}
+
+/*
+ * Name Resolution Functions
+ */
+
+/* return values of resolve_path()
+ * > 0 : return the length of the path
+ * < 0 : return error
+ */
+s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname)
+{
+ bool lossy = false;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+
+ if (strscpy(name_buf, path, sizeof(name_buf)) < 0)
+ return FFS_INVALIDPATH;
+
+ nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy);
+ if (lossy)
+ return FFS_INVALIDPATH;
+
+ fid->size = i_size_read(inode);
+
+ p_dir->dir = fid->start_clu;
+ p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits);
+ p_dir->flags = fid->flags;
+
+ return FFS_SUCCESS;
+}
+
+/*
+ * File Operation Functions
+ */
+static struct fs_func fat_fs_func = {
+ .alloc_cluster = fat_alloc_cluster,
+ .free_cluster = fat_free_cluster,
+ .count_used_clusters = fat_count_used_clusters,
+
+ .init_dir_entry = fat_init_dir_entry,
+ .init_ext_entry = fat_init_ext_entry,
+ .find_dir_entry = fat_find_dir_entry,
+ .delete_dir_entry = fat_delete_dir_entry,
+ .get_uni_name_from_ext_entry = fat_get_uni_name_from_ext_entry,
+ .count_ext_entries = fat_count_ext_entries,
+ .calc_num_entries = fat_calc_num_entries,
+
+ .get_entry_type = fat_get_entry_type,
+ .set_entry_type = fat_set_entry_type,
+ .get_entry_attr = fat_get_entry_attr,
+ .set_entry_attr = fat_set_entry_attr,
+ .get_entry_flag = fat_get_entry_flag,
+ .set_entry_flag = fat_set_entry_flag,
+ .get_entry_clu0 = fat_get_entry_clu0,
+ .set_entry_clu0 = fat_set_entry_clu0,
+ .get_entry_size = fat_get_entry_size,
+ .set_entry_size = fat_set_entry_size,
+ .get_entry_time = fat_get_entry_time,
+ .set_entry_time = fat_set_entry_time,
+};
+
+s32 fat16_mount(struct super_block *sb, struct pbr_sector_t *p_pbr)
+{
+ s32 num_reserved, num_root_sectors;
+ struct bpb16_t *p_bpb = (struct bpb16_t *)p_pbr->bpb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ if (p_bpb->num_fats == 0)
+ return FFS_FORMATERR;
+
+ num_root_sectors = GET16(p_bpb->num_root_entries) << DENTRY_SIZE_BITS;
+ num_root_sectors = ((num_root_sectors - 1) >>
+ p_bd->sector_size_bits) + 1;
+
+ p_fs->sectors_per_clu = p_bpb->sectors_per_clu;
+ p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu);
+ p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits +
+ p_bd->sector_size_bits;
+ p_fs->cluster_size = 1 << p_fs->cluster_size_bits;
+
+ p_fs->num_FAT_sectors = GET16(p_bpb->num_fat_sectors);
+
+ p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved);
+ if (p_bpb->num_fats == 1)
+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
+ else
+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector +
+ p_fs->num_FAT_sectors;
+
+ p_fs->root_start_sector = p_fs->FAT2_start_sector +
+ p_fs->num_FAT_sectors;
+ p_fs->data_start_sector = p_fs->root_start_sector + num_root_sectors;
+
+ p_fs->num_sectors = GET16(p_bpb->num_sectors);
+ if (p_fs->num_sectors == 0)
+ p_fs->num_sectors = GET32(p_bpb->num_huge_sectors);
+
+ num_reserved = p_fs->data_start_sector - p_fs->PBR_sector;
+ p_fs->num_clusters = ((p_fs->num_sectors - num_reserved) >>
+ p_fs->sectors_per_clu_bits) + 2;
+ /* because the cluster index starts with 2 */
+
+ if (p_fs->num_clusters < FAT12_THRESHOLD)
+ p_fs->vol_type = FAT12;
+ else
+ p_fs->vol_type = FAT16;
+ p_fs->vol_id = GET32(p_bpb->vol_serial);
+
+ p_fs->root_dir = 0;
+ p_fs->dentries_in_root = GET16(p_bpb->num_root_entries);
+ p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits -
+ DENTRY_SIZE_BITS);
+
+ p_fs->vol_flag = VOL_CLEAN;
+ p_fs->clu_srch_ptr = 2;
+ p_fs->used_clusters = UINT_MAX;
+
+ p_fs->fs_func = &fat_fs_func;
+
+ return FFS_SUCCESS;
+}
+
+s32 fat32_mount(struct super_block *sb, struct pbr_sector_t *p_pbr)
+{
+ s32 num_reserved;
+ struct bpb32_t *p_bpb = (struct bpb32_t *)p_pbr->bpb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ if (p_bpb->num_fats == 0)
+ return FFS_FORMATERR;
+
+ p_fs->sectors_per_clu = p_bpb->sectors_per_clu;
+ p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu);
+ p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits +
+ p_bd->sector_size_bits;
+ p_fs->cluster_size = 1 << p_fs->cluster_size_bits;
+
+ p_fs->num_FAT_sectors = GET32(p_bpb->num_fat32_sectors);
+
+ p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved);
+ if (p_bpb->num_fats == 1)
+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
+ else
+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector +
+ p_fs->num_FAT_sectors;
+
+ p_fs->root_start_sector = p_fs->FAT2_start_sector +
+ p_fs->num_FAT_sectors;
+ p_fs->data_start_sector = p_fs->root_start_sector;
+
+ p_fs->num_sectors = GET32(p_bpb->num_huge_sectors);
+ num_reserved = p_fs->data_start_sector - p_fs->PBR_sector;
+
+ p_fs->num_clusters = ((p_fs->num_sectors - num_reserved) >>
+ p_fs->sectors_per_clu_bits) + 2;
+ /* because the cluster index starts with 2 */
+
+ p_fs->vol_type = FAT32;
+ p_fs->vol_id = GET32(p_bpb->vol_serial);
+
+ p_fs->root_dir = GET32(p_bpb->root_cluster);
+ p_fs->dentries_in_root = 0;
+ p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits -
+ DENTRY_SIZE_BITS);
+
+ p_fs->vol_flag = VOL_CLEAN;
+ p_fs->clu_srch_ptr = 2;
+ p_fs->used_clusters = UINT_MAX;
+
+ p_fs->fs_func = &fat_fs_func;
+
+ return FFS_SUCCESS;
+}
+
+static struct fs_func exfat_fs_func = {
+ .alloc_cluster = exfat_alloc_cluster,
+ .free_cluster = exfat_free_cluster,
+ .count_used_clusters = exfat_count_used_clusters,
+
+ .init_dir_entry = exfat_init_dir_entry,
+ .init_ext_entry = exfat_init_ext_entry,
+ .find_dir_entry = exfat_find_dir_entry,
+ .delete_dir_entry = exfat_delete_dir_entry,
+ .get_uni_name_from_ext_entry = exfat_get_uni_name_from_ext_entry,
+ .count_ext_entries = exfat_count_ext_entries,
+ .calc_num_entries = exfat_calc_num_entries,
+
+ .get_entry_type = exfat_get_entry_type,
+ .set_entry_type = exfat_set_entry_type,
+ .get_entry_attr = exfat_get_entry_attr,
+ .set_entry_attr = exfat_set_entry_attr,
+ .get_entry_flag = exfat_get_entry_flag,
+ .set_entry_flag = exfat_set_entry_flag,
+ .get_entry_clu0 = exfat_get_entry_clu0,
+ .set_entry_clu0 = exfat_set_entry_clu0,
+ .get_entry_size = exfat_get_entry_size,
+ .set_entry_size = exfat_set_entry_size,
+ .get_entry_time = exfat_get_entry_time,
+ .set_entry_time = exfat_set_entry_time,
+};
+
+s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr)
+{
+ struct bpbex_t *p_bpb = (struct bpbex_t *)p_pbr->bpb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ if (p_bpb->num_fats == 0)
+ return FFS_FORMATERR;
+
+ p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits;
+ p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits;
+ p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits +
+ p_bd->sector_size_bits;
+ p_fs->cluster_size = 1 << p_fs->cluster_size_bits;
+
+ p_fs->num_FAT_sectors = GET32(p_bpb->fat_length);
+
+ p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset);
+ if (p_bpb->num_fats == 1)
+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
+ else
+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector +
+ p_fs->num_FAT_sectors;
+
+ p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset);
+ p_fs->data_start_sector = p_fs->root_start_sector;
+
+ p_fs->num_sectors = GET64(p_bpb->vol_length);
+ p_fs->num_clusters = GET32(p_bpb->clu_count) + 2;
+ /* because the cluster index starts with 2 */
+
+ p_fs->vol_type = EXFAT;
+ p_fs->vol_id = GET32(p_bpb->vol_serial);
+
+ p_fs->root_dir = GET32(p_bpb->root_cluster);
+ p_fs->dentries_in_root = 0;
+ p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits -
+ DENTRY_SIZE_BITS);
+
+ p_fs->vol_flag = (u32)GET16(p_bpb->vol_flags);
+ p_fs->clu_srch_ptr = 2;
+ p_fs->used_clusters = UINT_MAX;
+
+ p_fs->fs_func = &exfat_fs_func;
+
+ return FFS_SUCCESS;
+}
+
+s32 create_dir(struct inode *inode, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, struct file_id_t *fid)
+{
+ s32 ret, dentry, num_entries;
+ u64 size;
+ struct chain_t clu;
+ struct dos_name_t dos_name, dot_name;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct fs_func *fs_func = p_fs->fs_func;
+
+ ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries,
+ &dos_name);
+ if (ret)
+ return ret;
+
+ /* find_empty_entry must be called before alloc_cluster */
+ dentry = find_empty_entry(inode, p_dir, num_entries);
+ if (dentry < 0)
+ return FFS_FULL;
+
+ clu.dir = CLUSTER_32(~0);
+ clu.size = 0;
+ clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
+
+ /* (1) allocate a cluster */
+ ret = fs_func->alloc_cluster(sb, 1, &clu);
+ if (ret < 0)
+ return FFS_MEDIAERR;
+ else if (ret == 0)
+ return FFS_FULL;
+
+ ret = clear_cluster(sb, clu.dir);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ if (p_fs->vol_type == EXFAT) {
+ size = p_fs->cluster_size;
+ } else {
+ size = 0;
+
+ /* initialize the . and .. entry
+ * Information for . points to itself
+ * Information for .. points to parent dir
+ */
+
+ dot_name.name_case = 0x0;
+ memcpy(dot_name.name, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH);
+
+ ret = fs_func->init_dir_entry(sb, &clu, 0, TYPE_DIR, clu.dir,
+ 0);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ ret = fs_func->init_ext_entry(sb, &clu, 0, 1, NULL, &dot_name);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ memcpy(dot_name.name, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH);
+
+ if (p_dir->dir == p_fs->root_dir)
+ ret = fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR,
+ CLUSTER_32(0), 0);
+ else
+ ret = fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR,
+ p_dir->dir, 0);
+
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ ret = p_fs->fs_func->init_ext_entry(sb, &clu, 1, 1, NULL,
+ &dot_name);
+ if (ret != FFS_SUCCESS)
+ return ret;
+ }
+
+ /* (2) update the directory entry */
+ /* make sub-dir entry in parent directory */
+ ret = fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir,
+ size);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ ret = fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname,
+ &dos_name);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ fid->dir.dir = p_dir->dir;
+ fid->dir.size = p_dir->size;
+ fid->dir.flags = p_dir->flags;
+ fid->entry = dentry;
+
+ fid->attr = ATTR_SUBDIR;
+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
+ fid->size = size;
+ fid->start_clu = clu.dir;
+
+ fid->type = TYPE_DIR;
+ fid->rwoffset = 0;
+ fid->hint_last_off = -1;
+
+ return FFS_SUCCESS;
+}
+
+s32 create_file(struct inode *inode, struct chain_t *p_dir,
+ struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid)
+{
+ s32 ret, dentry, num_entries;
+ struct dos_name_t dos_name;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct fs_func *fs_func = p_fs->fs_func;
+
+ ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries,
+ &dos_name);
+ if (ret)
+ return ret;
+
+ /* find_empty_entry must be called before alloc_cluster() */
+ dentry = find_empty_entry(inode, p_dir, num_entries);
+ if (dentry < 0)
+ return FFS_FULL;
+
+ /* (1) update the directory entry */
+ /* fill the dos name directory entry information of the created file.
+ * the first cluster is not determined yet. (0)
+ */
+ ret = fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode,
+ CLUSTER_32(0), 0);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ ret = fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname,
+ &dos_name);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ fid->dir.dir = p_dir->dir;
+ fid->dir.size = p_dir->size;
+ fid->dir.flags = p_dir->flags;
+ fid->entry = dentry;
+
+ fid->attr = ATTR_ARCHIVE | mode;
+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
+ fid->size = 0;
+ fid->start_clu = CLUSTER_32(~0);
+
+ fid->type = TYPE_FILE;
+ fid->rwoffset = 0;
+ fid->hint_last_off = -1;
+
+ return FFS_SUCCESS;
+}
+
+void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry)
+{
+ s32 num_entries;
+ sector_t sector;
+ struct dentry_t *ep;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct fs_func *fs_func = p_fs->fs_func;
+
+ ep = get_entry_in_dir(sb, p_dir, entry, &sector);
+ if (!ep)
+ return;
+
+ buf_lock(sb, sector);
+
+ /* buf_lock() before call count_ext_entries() */
+ num_entries = fs_func->count_ext_entries(sb, p_dir, entry, ep);
+ if (num_entries < 0) {
+ buf_unlock(sb, sector);
+ return;
+ }
+ num_entries++;
+
+ buf_unlock(sb, sector);
+
+ /* (1) update the directory entry */
+ fs_func->delete_dir_entry(sb, p_dir, entry, 0, num_entries);
+}
+
+s32 rename_file(struct inode *inode, struct chain_t *p_dir, s32 oldentry,
+ struct uni_name_t *p_uniname, struct file_id_t *fid)
+{
+ s32 ret, newentry = -1, num_old_entries, num_new_entries;
+ sector_t sector_old, sector_new;
+ struct dos_name_t dos_name;
+ struct dentry_t *epold, *epnew;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct fs_func *fs_func = p_fs->fs_func;
+
+ epold = get_entry_in_dir(sb, p_dir, oldentry, &sector_old);
+ if (!epold)
+ return FFS_MEDIAERR;
+
+ buf_lock(sb, sector_old);
+
+ /* buf_lock() before call count_ext_entries() */
+ num_old_entries = fs_func->count_ext_entries(sb, p_dir, oldentry,
+ epold);
+ if (num_old_entries < 0) {
+ buf_unlock(sb, sector_old);
+ return FFS_MEDIAERR;
+ }
+ num_old_entries++;
+
+ ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname,
+ &num_new_entries, &dos_name);
+ if (ret) {
+ buf_unlock(sb, sector_old);
+ return ret;
+ }
+
+ if (num_old_entries < num_new_entries) {
+ newentry = find_empty_entry(inode, p_dir, num_new_entries);
+ if (newentry < 0) {
+ buf_unlock(sb, sector_old);
+ return FFS_FULL;
+ }
+
+ epnew = get_entry_in_dir(sb, p_dir, newentry, &sector_new);
+ if (!epnew) {
+ buf_unlock(sb, sector_old);
+ return FFS_MEDIAERR;
+ }
+
+ memcpy((void *)epnew, (void *)epold, DENTRY_SIZE);
+ if (fs_func->get_entry_type(epnew) == TYPE_FILE) {
+ fs_func->set_entry_attr(epnew,
+ fs_func->get_entry_attr(epnew) |
+ ATTR_ARCHIVE);
+ fid->attr |= ATTR_ARCHIVE;
+ }
+ buf_modify(sb, sector_new);
+ buf_unlock(sb, sector_old);
+
+ if (p_fs->vol_type == EXFAT) {
+ epold = get_entry_in_dir(sb, p_dir, oldentry + 1,
+ &sector_old);
+ buf_lock(sb, sector_old);
+ epnew = get_entry_in_dir(sb, p_dir, newentry + 1,
+ &sector_new);
+
+ if (!epold || !epnew) {
+ buf_unlock(sb, sector_old);
+ return FFS_MEDIAERR;
+ }
+
+ memcpy((void *)epnew, (void *)epold, DENTRY_SIZE);
+ buf_modify(sb, sector_new);
+ buf_unlock(sb, sector_old);
+ }
+
+ ret = fs_func->init_ext_entry(sb, p_dir, newentry,
+ num_new_entries, p_uniname,
+ &dos_name);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ fs_func->delete_dir_entry(sb, p_dir, oldentry, 0,
+ num_old_entries);
+ fid->entry = newentry;
+ } else {
+ if (fs_func->get_entry_type(epold) == TYPE_FILE) {
+ fs_func->set_entry_attr(epold,
+ fs_func->get_entry_attr(epold) |
+ ATTR_ARCHIVE);
+ fid->attr |= ATTR_ARCHIVE;
+ }
+ buf_modify(sb, sector_old);
+ buf_unlock(sb, sector_old);
+
+ ret = fs_func->init_ext_entry(sb, p_dir, oldentry,
+ num_new_entries, p_uniname,
+ &dos_name);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ fs_func->delete_dir_entry(sb, p_dir, oldentry, num_new_entries,
+ num_old_entries);
+ }
+
+ return FFS_SUCCESS;
+}
+
+s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry,
+ struct chain_t *p_newdir, struct uni_name_t *p_uniname,
+ struct file_id_t *fid)
+{
+ s32 ret, newentry, num_new_entries, num_old_entries;
+ sector_t sector_mov, sector_new;
+ struct chain_t clu;
+ struct dos_name_t dos_name;
+ struct dentry_t *epmov, *epnew;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct fs_func *fs_func = p_fs->fs_func;
+
+ epmov = get_entry_in_dir(sb, p_olddir, oldentry, &sector_mov);
+ if (!epmov)
+ return FFS_MEDIAERR;
+
+ /* check if the source and target directory is the same */
+ if (fs_func->get_entry_type(epmov) == TYPE_DIR &&
+ fs_func->get_entry_clu0(epmov) == p_newdir->dir)
+ return FFS_INVALIDPATH;
+
+ buf_lock(sb, sector_mov);
+
+ /* buf_lock() before call count_ext_entries() */
+ num_old_entries = fs_func->count_ext_entries(sb, p_olddir, oldentry,
+ epmov);
+ if (num_old_entries < 0) {
+ buf_unlock(sb, sector_mov);
+ return FFS_MEDIAERR;
+ }
+ num_old_entries++;
+
+ ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname,
+ &num_new_entries, &dos_name);
+ if (ret) {
+ buf_unlock(sb, sector_mov);
+ return ret;
+ }
+
+ newentry = find_empty_entry(inode, p_newdir, num_new_entries);
+ if (newentry < 0) {
+ buf_unlock(sb, sector_mov);
+ return FFS_FULL;
+ }
+
+ epnew = get_entry_in_dir(sb, p_newdir, newentry, &sector_new);
+ if (!epnew) {
+ buf_unlock(sb, sector_mov);
+ return FFS_MEDIAERR;
+ }
+
+ memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE);
+ if (fs_func->get_entry_type(epnew) == TYPE_FILE) {
+ fs_func->set_entry_attr(epnew, fs_func->get_entry_attr(epnew) |
+ ATTR_ARCHIVE);
+ fid->attr |= ATTR_ARCHIVE;
+ }
+ buf_modify(sb, sector_new);
+ buf_unlock(sb, sector_mov);
+
+ if (p_fs->vol_type == EXFAT) {
+ epmov = get_entry_in_dir(sb, p_olddir, oldentry + 1,
+ &sector_mov);
+ buf_lock(sb, sector_mov);
+ epnew = get_entry_in_dir(sb, p_newdir, newentry + 1,
+ &sector_new);
+ if (!epmov || !epnew) {
+ buf_unlock(sb, sector_mov);
+ return FFS_MEDIAERR;
+ }
+
+ memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE);
+ buf_modify(sb, sector_new);
+ buf_unlock(sb, sector_mov);
+ } else if (fs_func->get_entry_type(epnew) == TYPE_DIR) {
+ /* change ".." pointer to new parent dir */
+ clu.dir = fs_func->get_entry_clu0(epnew);
+ clu.flags = 0x01;
+
+ epnew = get_entry_in_dir(sb, &clu, 1, &sector_new);
+ if (!epnew)
+ return FFS_MEDIAERR;
+
+ if (p_newdir->dir == p_fs->root_dir)
+ fs_func->set_entry_clu0(epnew, CLUSTER_32(0));
+ else
+ fs_func->set_entry_clu0(epnew, p_newdir->dir);
+ buf_modify(sb, sector_new);
+ }
+
+ ret = fs_func->init_ext_entry(sb, p_newdir, newentry, num_new_entries,
+ p_uniname, &dos_name);
+ if (ret != FFS_SUCCESS)
+ return ret;
+
+ fs_func->delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries);
+
+ fid->dir.dir = p_newdir->dir;
+ fid->dir.size = p_newdir->size;
+ fid->dir.flags = p_newdir->flags;
+
+ fid->entry = newentry;
+
+ return FFS_SUCCESS;
+}
+
+/*
+ * Sector Read/Write Functions
+ */
+
+int sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh,
+ bool read)
+{
+ s32 ret = FFS_MEDIAERR;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if ((sec >= (p_fs->PBR_sector + p_fs->num_sectors)) &&
+ (p_fs->num_sectors > 0)) {
+ pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n",
+ __func__, (unsigned long long)sec);
+ fs_error(sb);
+ return ret;
+ }
+
+ if (!p_fs->dev_ejected) {
+ ret = bdev_read(sb, sec, bh, 1, read);
+ if (ret != FFS_SUCCESS)
+ p_fs->dev_ejected = 1;
+ }
+
+ return ret;
+}
+
+int sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh,
+ bool sync)
+{
+ s32 ret = FFS_MEDIAERR;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (sec >= (p_fs->PBR_sector + p_fs->num_sectors) &&
+ (p_fs->num_sectors > 0)) {
+ pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n",
+ __func__, (unsigned long long)sec);
+ fs_error(sb);
+ return ret;
+ }
+
+ if (!bh) {
+ pr_err("[EXFAT] %s: bh is NULL!\n", __func__);
+ fs_error(sb);
+ return ret;
+ }
+
+ if (!p_fs->dev_ejected) {
+ ret = bdev_write(sb, sec, bh, 1, sync);
+ if (ret != FFS_SUCCESS)
+ p_fs->dev_ejected = 1;
+ }
+
+ return ret;
+}
+
+int multi_sector_read(struct super_block *sb, sector_t sec,
+ struct buffer_head **bh, s32 num_secs, bool read)
+{
+ s32 ret = FFS_MEDIAERR;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors)) &&
+ (p_fs->num_sectors > 0)) {
+ pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n",
+ __func__, (unsigned long long)sec, num_secs);
+ fs_error(sb);
+ return ret;
+ }
+
+ if (!p_fs->dev_ejected) {
+ ret = bdev_read(sb, sec, bh, num_secs, read);
+ if (ret != FFS_SUCCESS)
+ p_fs->dev_ejected = 1;
+ }
+
+ return ret;
+}
+
+int multi_sector_write(struct super_block *sb, sector_t sec,
+ struct buffer_head *bh, s32 num_secs, bool sync)
+{
+ s32 ret = FFS_MEDIAERR;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if ((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors) &&
+ (p_fs->num_sectors > 0)) {
+ pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n",
+ __func__, (unsigned long long)sec, num_secs);
+ fs_error(sb);
+ return ret;
+ }
+ if (!bh) {
+ pr_err("[EXFAT] %s: bh is NULL!\n", __func__);
+ fs_error(sb);
+ return ret;
+ }
+
+ if (!p_fs->dev_ejected) {
+ ret = bdev_write(sb, sec, bh, num_secs, sync);
+ if (ret != FFS_SUCCESS)
+ p_fs->dev_ejected = 1;
+ }
+
+ return ret;
+}
diff --git a/drivers/staging/exfat/exfat_nls.c b/drivers/staging/exfat/exfat_nls.c
new file mode 100644
index 000000000000..03cb8290b5d2
--- /dev/null
+++ b/drivers/staging/exfat/exfat_nls.c
@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/string.h>
+#include <linux/nls.h>
+#include "exfat.h"
+
+static u16 bad_dos_chars[] = {
+ /* + , ; = [ ] */
+ 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D,
+ 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D,
+ 0
+};
+
+static u16 bad_uni_chars[] = {
+ /* " * / : < > ? \ | */
+ 0x0022, 0x002A, 0x002F, 0x003A,
+ 0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
+ 0
+};
+
+static int convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch,
+ bool *lossy)
+{
+ int len;
+
+ *uni = 0x0;
+
+ if (ch[0] < 0x80) {
+ *uni = (u16)ch[0];
+ return 1;
+ }
+
+ len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni);
+ if (len < 0) {
+ /* conversion failed */
+ pr_info("%s: fail to use nls\n", __func__);
+ if (lossy)
+ *lossy = true;
+ *uni = (u16)'_';
+ if (!strcmp(nls->charset, "utf8"))
+ return 1;
+ else
+ return 2;
+ }
+
+ return len;
+}
+
+static int convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni,
+ bool *lossy)
+{
+ int len;
+
+ ch[0] = 0x0;
+
+ if (uni < 0x0080) {
+ ch[0] = (u8)uni;
+ return 1;
+ }
+
+ len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE);
+ if (len < 0) {
+ /* conversion failed */
+ pr_info("%s: fail to use nls\n", __func__);
+ if (lossy)
+ *lossy = true;
+ ch[0] = '_';
+ return 1;
+ }
+
+ return len;
+}
+
+u16 nls_upper(struct super_block *sb, u16 a)
+{
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ if (EXFAT_SB(sb)->options.casesensitive)
+ return a;
+ if (p_fs->vol_utbl && p_fs->vol_utbl[get_col_index(a)])
+ return p_fs->vol_utbl[get_col_index(a)][get_row_index(a)];
+ else
+ return a;
+}
+
+static u16 *nls_wstrchr(u16 *str, u16 wchar)
+{
+ while (*str) {
+ if (*(str++) == wchar)
+ return str;
+ }
+
+ return NULL;
+}
+
+int nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b)
+{
+ return strncmp(a, b, DOS_NAME_LENGTH);
+}
+
+int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b)
+{
+ int i;
+
+ for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
+ if (nls_upper(sb, *a) != nls_upper(sb, *b))
+ return 1;
+ if (*a == 0x0)
+ return 0;
+ }
+ return 0;
+}
+
+void nls_uniname_to_dosname(struct super_block *sb,
+ struct dos_name_t *p_dosname,
+ struct uni_name_t *p_uniname, bool *p_lossy)
+{
+ int i, j, len;
+ bool lossy = false;
+ u8 buf[MAX_CHARSET_SIZE];
+ u8 lower = 0, upper = 0;
+ u8 *dosname = p_dosname->name;
+ u16 *uniname = p_uniname->name;
+ u16 *p, *last_period;
+ struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
+
+ for (i = 0; i < DOS_NAME_LENGTH; i++)
+ *(dosname + i) = ' ';
+
+ if (!nls_uniname_cmp(sb, uniname, (u16 *)UNI_CUR_DIR_NAME)) {
+ *(dosname) = '.';
+ p_dosname->name_case = 0x0;
+ if (p_lossy)
+ *p_lossy = false;
+ return;
+ }
+
+ if (!nls_uniname_cmp(sb, uniname, (u16 *)UNI_PAR_DIR_NAME)) {
+ *(dosname) = '.';
+ *(dosname + 1) = '.';
+ p_dosname->name_case = 0x0;
+ if (p_lossy)
+ *p_lossy = false;
+ return;
+ }
+
+ /* search for the last embedded period */
+ last_period = NULL;
+ for (p = uniname; *p; p++) {
+ if (*p == (u16)'.')
+ last_period = p;
+ }
+
+ i = 0;
+ while (i < DOS_NAME_LENGTH) {
+ if (i == 8) {
+ if (!last_period)
+ break;
+
+ if (uniname <= last_period) {
+ if (uniname < last_period)
+ lossy = true;
+ uniname = last_period + 1;
+ }
+ }
+
+ if (*uniname == (u16)'\0') {
+ break;
+ } else if (*uniname == (u16)' ') {
+ lossy = true;
+ } else if (*uniname == (u16)'.') {
+ if (uniname < last_period)
+ lossy = true;
+ else
+ i = 8;
+ } else if (nls_wstrchr(bad_dos_chars, *uniname)) {
+ lossy = true;
+ *(dosname + i) = '_';
+ i++;
+ } else {
+ len = convert_uni_to_ch(nls, buf, *uniname, &lossy);
+
+ if (len > 1) {
+ if ((i >= 8) && ((i + len) > DOS_NAME_LENGTH))
+ break;
+
+ if ((i < 8) && ((i + len) > 8)) {
+ i = 8;
+ continue;
+ }
+
+ lower = 0xFF;
+
+ for (j = 0; j < len; j++, i++)
+ *(dosname + i) = *(buf + j);
+ } else { /* len == 1 */
+ if ((*buf >= 'a') && (*buf <= 'z')) {
+ *(dosname + i) = *buf - ('a' - 'A');
+
+ if (i < 8)
+ lower |= 0x08;
+ else
+ lower |= 0x10;
+ } else if ((*buf >= 'A') && (*buf <= 'Z')) {
+ *(dosname + i) = *buf;
+
+ if (i < 8)
+ upper |= 0x08;
+ else
+ upper |= 0x10;
+ } else {
+ *(dosname + i) = *buf;
+ }
+ i++;
+ }
+ }
+
+ uniname++;
+ }
+
+ if (*dosname == 0xE5)
+ *dosname = 0x05;
+
+ if (*uniname != 0x0)
+ lossy = true;
+
+ if (upper & lower)
+ p_dosname->name_case = 0xFF;
+ else
+ p_dosname->name_case = lower;
+
+ if (p_lossy)
+ *p_lossy = lossy;
+}
+
+void nls_dosname_to_uniname(struct super_block *sb,
+ struct uni_name_t *p_uniname,
+ struct dos_name_t *p_dosname)
+{
+ int i = 0, j, n = 0;
+ u8 buf[DOS_NAME_LENGTH + 2];
+ u8 *dosname = p_dosname->name;
+ u16 *uniname = p_uniname->name;
+ struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
+
+ if (*dosname == 0x05) {
+ *buf = 0xE5;
+ i++;
+ n++;
+ }
+
+ for (; i < 8; i++, n++) {
+ if (*(dosname + i) == ' ')
+ break;
+
+ if ((*(dosname + i) >= 'A') && (*(dosname + i) <= 'Z') &&
+ (p_dosname->name_case & 0x08))
+ *(buf + n) = *(dosname + i) + ('a' - 'A');
+ else
+ *(buf + n) = *(dosname + i);
+ }
+ if (*(dosname + 8) != ' ') {
+ *(buf + n) = '.';
+ n++;
+ }
+
+ for (i = 8; i < DOS_NAME_LENGTH; i++, n++) {
+ if (*(dosname + i) == ' ')
+ break;
+
+ if ((*(dosname + i) >= 'A') && (*(dosname + i) <= 'Z') &&
+ (p_dosname->name_case & 0x10))
+ *(buf + n) = *(dosname + i) + ('a' - 'A');
+ else
+ *(buf + n) = *(dosname + i);
+ }
+ *(buf + n) = '\0';
+
+ i = 0;
+ j = 0;
+ while (j < (MAX_NAME_LENGTH - 1)) {
+ if (*(buf + i) == '\0')
+ break;
+
+ i += convert_ch_to_uni(nls, uniname, (buf + i), NULL);
+
+ uniname++;
+ j++;
+ }
+
+ *uniname = (u16)'\0';
+}
+
+void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring,
+ struct uni_name_t *p_uniname)
+{
+ int i, j, len;
+ u8 buf[MAX_CHARSET_SIZE];
+ u16 *uniname = p_uniname->name;
+ struct nls_table *nls = EXFAT_SB(sb)->nls_io;
+
+ if (!nls) {
+ len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH,
+ UTF16_HOST_ENDIAN, p_cstring,
+ MAX_NAME_LENGTH);
+ p_cstring[len] = 0;
+ return;
+ }
+
+ i = 0;
+ while (i < (MAX_NAME_LENGTH - 1)) {
+ if (*uniname == (u16)'\0')
+ break;
+
+ len = convert_uni_to_ch(nls, buf, *uniname, NULL);
+
+ if (len > 1) {
+ for (j = 0; j < len; j++)
+ *p_cstring++ = (char)*(buf + j);
+ } else { /* len == 1 */
+ *p_cstring++ = (char)*buf;
+ }
+
+ uniname++;
+ i++;
+ }
+
+ *p_cstring = '\0';
+}
+
+void nls_cstring_to_uniname(struct super_block *sb,
+ struct uni_name_t *p_uniname, u8 *p_cstring,
+ bool *p_lossy)
+{
+ int i, j;
+ bool lossy = false;
+ u8 *end_of_name;
+ u8 upname[MAX_NAME_LENGTH * 2];
+ u16 *uniname = p_uniname->name;
+ struct nls_table *nls = EXFAT_SB(sb)->nls_io;
+
+ /* strip all trailing spaces */
+ end_of_name = p_cstring + strlen(p_cstring);
+
+ while (*(--end_of_name) == ' ') {
+ if (end_of_name < p_cstring)
+ break;
+ }
+ *(++end_of_name) = '\0';
+
+ if (strcmp(p_cstring, ".") && strcmp(p_cstring, "..")) {
+ /* strip all trailing periods */
+ while (*(--end_of_name) == '.') {
+ if (end_of_name < p_cstring)
+ break;
+ }
+ *(++end_of_name) = '\0';
+ }
+
+ if (*p_cstring == '\0')
+ lossy = true;
+
+ if (!nls) {
+ i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH,
+ UTF16_HOST_ENDIAN, uniname,
+ MAX_NAME_LENGTH);
+ for (j = 0; j < i; j++)
+ SET16_A(upname + j * 2, nls_upper(sb, uniname[j]));
+ uniname[i] = '\0';
+ } else {
+ i = 0;
+ j = 0;
+ while (j < (MAX_NAME_LENGTH - 1)) {
+ if (*(p_cstring + i) == '\0')
+ break;
+
+ i += convert_ch_to_uni(nls, uniname,
+ (u8 *)(p_cstring + i), &lossy);
+
+ if ((*uniname < 0x0020) ||
+ nls_wstrchr(bad_uni_chars, *uniname))
+ lossy = true;
+
+ SET16_A(upname + j * 2, nls_upper(sb, *uniname));
+
+ uniname++;
+ j++;
+ }
+
+ if (*(p_cstring + i) != '\0')
+ lossy = true;
+ *uniname = (u16)'\0';
+ }
+
+ p_uniname->name_len = j;
+ p_uniname->name_hash = calc_checksum_2byte(upname, j << 1, 0,
+ CS_DEFAULT);
+
+ if (p_lossy)
+ *p_lossy = lossy;
+}
diff --git a/drivers/staging/exfat/exfat_super.c b/drivers/staging/exfat/exfat_super.c
new file mode 100644
index 000000000000..5f6caee819a6
--- /dev/null
+++ b/drivers/staging/exfat/exfat_super.c
@@ -0,0 +1,4049 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/pagemap.h>
+#include <linux/mpage.h>
+#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
+#include <linux/mount.h>
+#include <linux/vfs.h>
+#include <linux/aio.h>
+#include <linux/iversion.h>
+#include <linux/parser.h>
+#include <linux/uio.h>
+#include <linux/writeback.h>
+#include <linux/log2.h>
+#include <linux/hash.h>
+#include <linux/backing-dev.h>
+#include <linux/sched.h>
+#include <linux/fs_struct.h>
+#include <linux/namei.h>
+
+#include <linux/string.h>
+#include <linux/nls.h>
+#include <linux/mutex.h>
+#include <linux/swap.h>
+
+#define EXFAT_VERSION "1.3.0"
+
+#include "exfat.h"
+
+static struct kmem_cache *exfat_inode_cachep;
+
+static int exfat_default_codepage = CONFIG_EXFAT_DEFAULT_CODEPAGE;
+static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET;
+
+#define INC_IVERSION(x) (inode_inc_iversion(x))
+#define GET_IVERSION(x) (inode_peek_iversion_raw(x))
+#define SET_IVERSION(x, y) (inode_set_iversion(x, y))
+
+static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos);
+static int exfat_sync_inode(struct inode *inode);
+static struct inode *exfat_build_inode(struct super_block *sb,
+ struct file_id_t *fid, loff_t i_pos);
+static int exfat_write_inode(struct inode *inode,
+ struct writeback_control *wbc);
+static void exfat_write_super(struct super_block *sb);
+
+#define UNIX_SECS_1980 315532800L
+#define UNIX_SECS_2108 4354819200L
+
+/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
+static void exfat_time_fat2unix(struct timespec64 *ts, struct date_time_t *tp)
+{
+ ts->tv_sec = mktime64(tp->Year + 1980, tp->Month + 1, tp->Day,
+ tp->Hour, tp->Minute, tp->Second);
+
+ ts->tv_nsec = tp->MilliSecond * NSEC_PER_MSEC;
+}
+
+/* Convert linear UNIX date to a FAT time/date pair. */
+static void exfat_time_unix2fat(struct timespec64 *ts, struct date_time_t *tp)
+{
+ time64_t second = ts->tv_sec;
+ struct tm tm;
+
+ time64_to_tm(second, 0, &tm);
+
+ if (second < UNIX_SECS_1980) {
+ tp->MilliSecond = 0;
+ tp->Second = 0;
+ tp->Minute = 0;
+ tp->Hour = 0;
+ tp->Day = 1;
+ tp->Month = 1;
+ tp->Year = 0;
+ return;
+ }
+
+ if (second >= UNIX_SECS_2108) {
+ tp->MilliSecond = 999;
+ tp->Second = 59;
+ tp->Minute = 59;
+ tp->Hour = 23;
+ tp->Day = 31;
+ tp->Month = 12;
+ tp->Year = 127;
+ return;
+ }
+
+ tp->MilliSecond = ts->tv_nsec / NSEC_PER_MSEC;
+ tp->Second = tm.tm_sec;
+ tp->Minute = tm.tm_min;
+ tp->Hour = tm.tm_hour;
+ tp->Day = tm.tm_mday;
+ tp->Month = tm.tm_mon + 1;
+ tp->Year = tm.tm_year + 1900 - 1980;
+}
+
+struct timestamp_t *tm_current(struct timestamp_t *tp)
+{
+ time64_t second = ktime_get_real_seconds();
+ struct tm tm;
+
+ time64_to_tm(second, 0, &tm);
+
+ if (second < UNIX_SECS_1980) {
+ tp->sec = 0;
+ tp->min = 0;
+ tp->hour = 0;
+ tp->day = 1;
+ tp->mon = 1;
+ tp->year = 0;
+ return tp;
+ }
+
+ if (second >= UNIX_SECS_2108) {
+ tp->sec = 59;
+ tp->min = 59;
+ tp->hour = 23;
+ tp->day = 31;
+ tp->mon = 12;
+ tp->year = 127;
+ return tp;
+ }
+
+ tp->sec = tm.tm_sec;
+ tp->min = tm.tm_min;
+ tp->hour = tm.tm_hour;
+ tp->day = tm.tm_mday;
+ tp->mon = tm.tm_mon + 1;
+ tp->year = tm.tm_year + 1900 - 1980;
+
+ return tp;
+}
+
+static void __lock_super(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ mutex_lock(&sbi->s_lock);
+}
+
+static void __unlock_super(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ mutex_unlock(&sbi->s_lock);
+}
+
+static int __is_sb_dirty(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ return sbi->s_dirt;
+}
+
+static void __set_sb_clean(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ sbi->s_dirt = 0;
+}
+
+static int __exfat_revalidate(struct dentry *dentry)
+{
+ return 0;
+}
+
+static int exfat_revalidate(struct dentry *dentry, unsigned int flags)
+{
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+
+ if (dentry->d_inode)
+ return 1;
+ return __exfat_revalidate(dentry);
+}
+
+static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags)
+{
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+
+ if (dentry->d_inode)
+ return 1;
+
+ if (!flags)
+ return 0;
+
+ if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
+ return 0;
+
+ return __exfat_revalidate(dentry);
+}
+
+static unsigned int __exfat_striptail_len(unsigned int len, const char *name)
+{
+ while (len && name[len - 1] == '.')
+ len--;
+ return len;
+}
+
+static unsigned int exfat_striptail_len(const struct qstr *qstr)
+{
+ return __exfat_striptail_len(qstr->len, qstr->name);
+}
+
+static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr)
+{
+ qstr->hash = full_name_hash(dentry, qstr->name,
+ exfat_striptail_len(qstr));
+ return 0;
+}
+
+static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr)
+{
+ struct super_block *sb = dentry->d_sb;
+ const unsigned char *name;
+ unsigned int len;
+ unsigned long hash;
+
+ name = qstr->name;
+ len = exfat_striptail_len(qstr);
+
+ hash = init_name_hash(dentry);
+ while (len--)
+ hash = partial_name_hash(nls_upper(sb, *name++), hash);
+ qstr->hash = end_name_hash(hash);
+
+ return 0;
+}
+
+static int exfat_cmpi(const struct dentry *dentry, unsigned int len,
+ const char *str, const struct qstr *name)
+{
+ struct nls_table *t = EXFAT_SB(dentry->d_sb)->nls_io;
+ unsigned int alen, blen;
+
+ alen = exfat_striptail_len(name);
+ blen = __exfat_striptail_len(len, str);
+ if (alen == blen) {
+ if (!t) {
+ if (strncasecmp(name->name, str, alen) == 0)
+ return 0;
+ } else {
+ if (nls_strnicmp(t, name->name, str, alen) == 0)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int exfat_cmp(const struct dentry *dentry, unsigned int len,
+ const char *str, const struct qstr *name)
+{
+ unsigned int alen, blen;
+
+ alen = exfat_striptail_len(name);
+ blen = __exfat_striptail_len(len, str);
+ if (alen == blen) {
+ if (strncmp(name->name, str, alen) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+static const struct dentry_operations exfat_ci_dentry_ops = {
+ .d_revalidate = exfat_revalidate_ci,
+ .d_hash = exfat_d_hashi,
+ .d_compare = exfat_cmpi,
+};
+
+static const struct dentry_operations exfat_dentry_ops = {
+ .d_revalidate = exfat_revalidate,
+ .d_hash = exfat_d_hash,
+ .d_compare = exfat_cmp,
+};
+
+static DEFINE_SEMAPHORE(z_sem);
+
+static inline void fs_sync(struct super_block *sb, bool do_sync)
+{
+ if (do_sync)
+ bdev_sync(sb);
+}
+
+/*
+ * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to
+ * save ATTR_RO instead of ->i_mode.
+ *
+ * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only
+ * bit, it's just used as flag for app.
+ */
+static inline int exfat_mode_can_hold_ro(struct inode *inode)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
+
+ if (S_ISDIR(inode->i_mode))
+ return 0;
+
+ if ((~sbi->options.fs_fmask) & 0222)
+ return 1;
+ return 0;
+}
+
+/* Convert attribute bits and a mask to the UNIX mode. */
+static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, u32 attr,
+ mode_t mode)
+{
+ if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR))
+ mode &= ~0222;
+
+ if (attr & ATTR_SUBDIR)
+ return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
+ else if (attr & ATTR_SYMLINK)
+ return (mode & ~sbi->options.fs_dmask) | S_IFLNK;
+ else
+ return (mode & ~sbi->options.fs_fmask) | S_IFREG;
+}
+
+/* Return the FAT attribute byte for this inode */
+static inline u32 exfat_make_attr(struct inode *inode)
+{
+ if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222))
+ return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY;
+ else
+ return EXFAT_I(inode)->fid.attr;
+}
+
+static inline void exfat_save_attr(struct inode *inode, u32 attr)
+{
+ if (exfat_mode_can_hold_ro(inode))
+ EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK;
+ else
+ EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY);
+}
+
+static int ffsMountVol(struct super_block *sb)
+{
+ int i, ret;
+ struct pbr_sector_t *p_pbr;
+ struct buffer_head *tmp_bh = NULL;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ pr_info("[EXFAT] trying to mount...\n");
+
+ down(&z_sem);
+
+ buf_init(sb);
+
+ sema_init(&p_fs->v_sem, 1);
+ p_fs->dev_ejected = 0;
+
+ /* open the block device */
+ bdev_open(sb);
+
+ if (p_bd->sector_size < sb->s_blocksize) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ if (p_bd->sector_size > sb->s_blocksize)
+ sb_set_blocksize(sb, p_bd->sector_size);
+
+ /* read Sector 0 */
+ if (sector_read(sb, 0, &tmp_bh, 1) != FFS_SUCCESS) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+
+ p_fs->PBR_sector = 0;
+
+ p_pbr = (struct pbr_sector_t *)tmp_bh->b_data;
+
+ /* check the validity of PBR */
+ if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) {
+ brelse(tmp_bh);
+ bdev_close(sb);
+ ret = FFS_FORMATERR;
+ goto out;
+ }
+
+ /* fill fs_struct */
+ for (i = 0; i < 53; i++)
+ if (p_pbr->bpb[i])
+ break;
+
+ if (i < 53) {
+#ifdef CONFIG_EXFAT_DONT_MOUNT_VFAT
+ ret = -EINVAL;
+ printk(KERN_INFO "EXFAT: Attempted to mount VFAT filesystem\n");
+ goto out;
+#else
+ if (GET16(p_pbr->bpb + 11)) /* num_fat_sectors */
+ ret = fat16_mount(sb, p_pbr);
+ else
+ ret = fat32_mount(sb, p_pbr);
+#endif
+ } else {
+ ret = exfat_mount(sb, p_pbr);
+ }
+
+ brelse(tmp_bh);
+
+ if (ret) {
+ bdev_close(sb);
+ goto out;
+ }
+
+ if (p_fs->vol_type == EXFAT) {
+ ret = load_alloc_bitmap(sb);
+ if (ret) {
+ bdev_close(sb);
+ goto out;
+ }
+ ret = load_upcase_table(sb);
+ if (ret) {
+ free_alloc_bitmap(sb);
+ bdev_close(sb);
+ goto out;
+ }
+ }
+
+ if (p_fs->dev_ejected) {
+ if (p_fs->vol_type == EXFAT) {
+ free_upcase_table(sb);
+ free_alloc_bitmap(sb);
+ }
+ bdev_close(sb);
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+
+ pr_info("[EXFAT] mounted successfully\n");
+
+out:
+ up(&z_sem);
+
+ return ret;
+}
+
+static int ffsUmountVol(struct super_block *sb)
+{
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ int err = FFS_SUCCESS;
+
+ pr_info("[EXFAT] trying to unmount...\n");
+
+ down(&z_sem);
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+
+ if (p_fs->vol_type == EXFAT) {
+ free_upcase_table(sb);
+ free_alloc_bitmap(sb);
+ }
+
+ FAT_release_all(sb);
+ buf_release_all(sb);
+
+ /* close the block device */
+ bdev_close(sb);
+
+ if (p_fs->dev_ejected) {
+ pr_info("[EXFAT] unmounted with media errors. Device is already ejected.\n");
+ err = FFS_MEDIAERR;
+ }
+
+ buf_shutdown(sb);
+
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+ up(&z_sem);
+
+ pr_info("[EXFAT] unmounted successfully\n");
+
+ return err;
+}
+
+static int ffsGetVolInfo(struct super_block *sb, struct vol_info_t *info)
+{
+ int err = FFS_SUCCESS;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ /* check the validity of pointer parameters */
+ if (!info)
+ return FFS_ERROR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ if (p_fs->used_clusters == UINT_MAX)
+ p_fs->used_clusters = p_fs->fs_func->count_used_clusters(sb);
+
+ info->FatType = p_fs->vol_type;
+ info->ClusterSize = p_fs->cluster_size;
+ info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */
+ info->UsedClusters = p_fs->used_clusters;
+ info->FreeClusters = info->NumClusters - info->UsedClusters;
+
+ if (p_fs->dev_ejected)
+ err = FFS_MEDIAERR;
+
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return err;
+}
+
+static int ffsSyncVol(struct super_block *sb, bool do_sync)
+{
+ int err = FFS_SUCCESS;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ /* synchronize the file system */
+ fs_sync(sb, do_sync);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+
+ if (p_fs->dev_ejected)
+ err = FFS_MEDIAERR;
+
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return err;
+}
+
+/*----------------------------------------------------------------------*/
+/* File Operation Functions */
+/*----------------------------------------------------------------------*/
+
+static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid)
+{
+ int ret, dentry, num_entries;
+ struct chain_t dir;
+ struct uni_name_t uni_name;
+ struct dos_name_t dos_name;
+ struct dentry_t *ep, *ep2;
+ struct entry_set_cache_t *es = NULL;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ pr_debug("%s entered\n", __func__);
+
+ /* check the validity of pointer parameters */
+ if (!fid || !path || (*path == '\0'))
+ return FFS_ERROR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ /* check the validity of directory name in the given pathname */
+ ret = resolve_path(inode, path, &dir, &uni_name);
+ if (ret)
+ goto out;
+
+ ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries,
+ &dos_name);
+ if (ret)
+ goto out;
+
+ /* search the file name for directories */
+ dentry = p_fs->fs_func->find_dir_entry(sb, &dir, &uni_name, num_entries,
+ &dos_name, TYPE_ALL);
+ if (dentry < -1) {
+ ret = FFS_NOTFOUND;
+ goto out;
+ }
+
+ fid->dir.dir = dir.dir;
+ fid->dir.size = dir.size;
+ fid->dir.flags = dir.flags;
+ fid->entry = dentry;
+
+ if (dentry == -1) {
+ fid->type = TYPE_DIR;
+ fid->rwoffset = 0;
+ fid->hint_last_off = -1;
+
+ fid->attr = ATTR_SUBDIR;
+ fid->flags = 0x01;
+ fid->size = 0;
+ fid->start_clu = p_fs->root_dir;
+ } else {
+ if (p_fs->vol_type == EXFAT) {
+ es = get_entry_set_in_dir(sb, &dir, dentry,
+ ES_2_ENTRIES, &ep);
+ if (!es) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ ep2 = ep + 1;
+ } else {
+ ep = get_entry_in_dir(sb, &dir, dentry, NULL);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ ep2 = ep;
+ }
+
+ fid->type = p_fs->fs_func->get_entry_type(ep);
+ fid->rwoffset = 0;
+ fid->hint_last_off = -1;
+ fid->attr = p_fs->fs_func->get_entry_attr(ep);
+
+ fid->size = p_fs->fs_func->get_entry_size(ep2);
+ if ((fid->type == TYPE_FILE) && (fid->size == 0)) {
+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
+ fid->start_clu = CLUSTER_32(~0);
+ } else {
+ fid->flags = p_fs->fs_func->get_entry_flag(ep2);
+ fid->start_clu = p_fs->fs_func->get_entry_clu0(ep2);
+ }
+
+ if (p_fs->vol_type == EXFAT)
+ release_entry_set(es);
+ }
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+static int ffsCreateFile(struct inode *inode, char *path, u8 mode,
+ struct file_id_t *fid)
+{
+ struct chain_t dir;
+ struct uni_name_t uni_name;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ int ret;
+
+ /* check the validity of pointer parameters */
+ if (!fid || !path || (*path == '\0'))
+ return FFS_ERROR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ /* check the validity of directory name in the given pathname */
+ ret = resolve_path(inode, path, &dir, &uni_name);
+ if (ret)
+ goto out;
+
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ /* create a new file */
+ ret = create_file(inode, &dir, &uni_name, mode, fid);
+
+#ifdef CONFIG_EXFAT_DELAYED_SYNC
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+#endif
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+static int ffsReadFile(struct inode *inode, struct file_id_t *fid, void *buffer,
+ u64 count, u64 *rcount)
+{
+ s32 offset, sec_offset, clu_offset;
+ u32 clu;
+ int ret = 0;
+ sector_t LogSector;
+ u64 oneblkread, read_bytes;
+ struct buffer_head *tmp_bh = NULL;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ /* check the validity of the given file id */
+ if (!fid)
+ return FFS_INVALIDFID;
+
+ /* check the validity of pointer parameters */
+ if (!buffer)
+ return FFS_ERROR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ /* check if the given file ID is opened */
+ if (fid->type != TYPE_FILE) {
+ ret = FFS_PERMISSIONERR;
+ goto out;
+ }
+
+ if (fid->rwoffset > fid->size)
+ fid->rwoffset = fid->size;
+
+ if (count > (fid->size - fid->rwoffset))
+ count = fid->size - fid->rwoffset;
+
+ if (count == 0) {
+ if (rcount)
+ *rcount = 0;
+ ret = FFS_EOF;
+ goto out;
+ }
+
+ read_bytes = 0;
+
+ while (count > 0) {
+ clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits);
+ clu = fid->start_clu;
+
+ if (fid->flags == 0x03) {
+ clu += clu_offset;
+ } else {
+ /* hint information */
+ if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
+ (clu_offset >= fid->hint_last_off)) {
+ clu_offset -= fid->hint_last_off;
+ clu = fid->hint_last_clu;
+ }
+
+ while (clu_offset > 0) {
+ /* clu = FAT_read(sb, clu); */
+ if (FAT_read(sb, clu, &clu) == -1)
+ return FFS_MEDIAERR;
+
+ clu_offset--;
+ }
+ }
+
+ /* hint information */
+ fid->hint_last_off = (s32)(fid->rwoffset >>
+ p_fs->cluster_size_bits);
+ fid->hint_last_clu = clu;
+
+ /* byte offset in cluster */
+ offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1));
+
+ /* sector offset in cluster */
+ sec_offset = offset >> p_bd->sector_size_bits;
+
+ /* byte offset in sector */
+ offset &= p_bd->sector_size_mask;
+
+ LogSector = START_SECTOR(clu) + sec_offset;
+
+ oneblkread = (u64)(p_bd->sector_size - offset);
+ if (oneblkread > count)
+ oneblkread = count;
+
+ if ((offset == 0) && (oneblkread == p_bd->sector_size)) {
+ if (sector_read(sb, LogSector, &tmp_bh, 1) !=
+ FFS_SUCCESS)
+ goto err_out;
+ memcpy((char *)buffer + read_bytes,
+ (char *)tmp_bh->b_data, (s32)oneblkread);
+ } else {
+ if (sector_read(sb, LogSector, &tmp_bh, 1) !=
+ FFS_SUCCESS)
+ goto err_out;
+ memcpy((char *)buffer + read_bytes,
+ (char *)tmp_bh->b_data + offset,
+ (s32)oneblkread);
+ }
+ count -= oneblkread;
+ read_bytes += oneblkread;
+ fid->rwoffset += oneblkread;
+ }
+ brelse(tmp_bh);
+
+/* How did this ever work and not leak a brlse()?? */
+err_out:
+ /* set the size of read bytes */
+ if (rcount)
+ *rcount = read_bytes;
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+static int ffsWriteFile(struct inode *inode, struct file_id_t *fid,
+ void *buffer, u64 count, u64 *wcount)
+{
+ bool modified = false;
+ s32 offset, sec_offset, clu_offset;
+ s32 num_clusters, num_alloc, num_alloced = (s32)~0;
+ int ret = 0;
+ u32 clu, last_clu;
+ sector_t LogSector, sector = 0;
+ u64 oneblkwrite, write_bytes;
+ struct chain_t new_clu;
+ struct timestamp_t tm;
+ struct dentry_t *ep, *ep2;
+ struct entry_set_cache_t *es = NULL;
+ struct buffer_head *tmp_bh = NULL;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ /* check the validity of the given file id */
+ if (!fid)
+ return FFS_INVALIDFID;
+
+ /* check the validity of pointer parameters */
+ if (!buffer)
+ return FFS_ERROR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ /* check if the given file ID is opened */
+ if (fid->type != TYPE_FILE) {
+ ret = FFS_PERMISSIONERR;
+ goto out;
+ }
+
+ if (fid->rwoffset > fid->size)
+ fid->rwoffset = fid->size;
+
+ if (count == 0) {
+ if (wcount)
+ *wcount = 0;
+ ret = FFS_SUCCESS;
+ goto out;
+ }
+
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ if (fid->size == 0)
+ num_clusters = 0;
+ else
+ num_clusters = (s32)((fid->size - 1) >>
+ p_fs->cluster_size_bits) + 1;
+
+ write_bytes = 0;
+
+ while (count > 0) {
+ clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits);
+ clu = last_clu = fid->start_clu;
+
+ if (fid->flags == 0x03) {
+ if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) {
+ last_clu += clu_offset - 1;
+
+ if (clu_offset == num_clusters)
+ clu = CLUSTER_32(~0);
+ else
+ clu += clu_offset;
+ }
+ } else {
+ /* hint information */
+ if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
+ (clu_offset >= fid->hint_last_off)) {
+ clu_offset -= fid->hint_last_off;
+ clu = fid->hint_last_clu;
+ }
+
+ while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) {
+ last_clu = clu;
+ /* clu = FAT_read(sb, clu); */
+ if (FAT_read(sb, clu, &clu) == -1) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ clu_offset--;
+ }
+ }
+
+ if (clu == CLUSTER_32(~0)) {
+ num_alloc = (s32)((count - 1) >>
+ p_fs->cluster_size_bits) + 1;
+ new_clu.dir = (last_clu == CLUSTER_32(~0)) ?
+ CLUSTER_32(~0) : last_clu + 1;
+ new_clu.size = 0;
+ new_clu.flags = fid->flags;
+
+ /* (1) allocate a chain of clusters */
+ num_alloced = p_fs->fs_func->alloc_cluster(sb,
+ num_alloc,
+ &new_clu);
+ if (num_alloced == 0)
+ break;
+ if (num_alloced < 0) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+
+ /* (2) append to the FAT chain */
+ if (last_clu == CLUSTER_32(~0)) {
+ if (new_clu.flags == 0x01)
+ fid->flags = 0x01;
+ fid->start_clu = new_clu.dir;
+ modified = true;
+ } else {
+ if (new_clu.flags != fid->flags) {
+ exfat_chain_cont_cluster(sb,
+ fid->start_clu,
+ num_clusters);
+ fid->flags = 0x01;
+ modified = true;
+ }
+ if (new_clu.flags == 0x01)
+ FAT_write(sb, last_clu, new_clu.dir);
+ }
+
+ num_clusters += num_alloced;
+ clu = new_clu.dir;
+ }
+
+ /* hint information */
+ fid->hint_last_off = (s32)(fid->rwoffset >>
+ p_fs->cluster_size_bits);
+ fid->hint_last_clu = clu;
+
+ /* byte offset in cluster */
+ offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1));
+
+ /* sector offset in cluster */
+ sec_offset = offset >> p_bd->sector_size_bits;
+
+ /* byte offset in sector */
+ offset &= p_bd->sector_size_mask;
+
+ LogSector = START_SECTOR(clu) + sec_offset;
+
+ oneblkwrite = (u64)(p_bd->sector_size - offset);
+ if (oneblkwrite > count)
+ oneblkwrite = count;
+
+ if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) {
+ if (sector_read(sb, LogSector, &tmp_bh, 0) !=
+ FFS_SUCCESS)
+ goto err_out;
+ memcpy((char *)tmp_bh->b_data,
+ (char *)buffer + write_bytes, (s32)oneblkwrite);
+ if (sector_write(sb, LogSector, tmp_bh, 0) !=
+ FFS_SUCCESS) {
+ brelse(tmp_bh);
+ goto err_out;
+ }
+ } else {
+ if ((offset > 0) ||
+ ((fid->rwoffset + oneblkwrite) < fid->size)) {
+ if (sector_read(sb, LogSector, &tmp_bh, 1) !=
+ FFS_SUCCESS)
+ goto err_out;
+ } else {
+ if (sector_read(sb, LogSector, &tmp_bh, 0) !=
+ FFS_SUCCESS)
+ goto err_out;
+ }
+
+ memcpy((char *)tmp_bh->b_data + offset,
+ (char *)buffer + write_bytes, (s32)oneblkwrite);
+ if (sector_write(sb, LogSector, tmp_bh, 0) !=
+ FFS_SUCCESS) {
+ brelse(tmp_bh);
+ goto err_out;
+ }
+ }
+
+ count -= oneblkwrite;
+ write_bytes += oneblkwrite;
+ fid->rwoffset += oneblkwrite;
+
+ fid->attr |= ATTR_ARCHIVE;
+
+ if (fid->size < fid->rwoffset) {
+ fid->size = fid->rwoffset;
+ modified = true;
+ }
+ }
+
+ brelse(tmp_bh);
+
+ /* (3) update the direcoty entry */
+ if (p_fs->vol_type == EXFAT) {
+ es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry,
+ ES_ALL_ENTRIES, &ep);
+ if (!es)
+ goto err_out;
+ ep2 = ep + 1;
+ } else {
+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
+ if (!ep)
+ goto err_out;
+ ep2 = ep;
+ }
+
+ p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY);
+ p_fs->fs_func->set_entry_attr(ep, fid->attr);
+
+ if (p_fs->vol_type != EXFAT)
+ buf_modify(sb, sector);
+
+ if (modified) {
+ if (p_fs->fs_func->get_entry_flag(ep2) != fid->flags)
+ p_fs->fs_func->set_entry_flag(ep2, fid->flags);
+
+ if (p_fs->fs_func->get_entry_size(ep2) != fid->size)
+ p_fs->fs_func->set_entry_size(ep2, fid->size);
+
+ if (p_fs->fs_func->get_entry_clu0(ep2) != fid->start_clu)
+ p_fs->fs_func->set_entry_clu0(ep2, fid->start_clu);
+
+ if (p_fs->vol_type != EXFAT)
+ buf_modify(sb, sector);
+ }
+
+ if (p_fs->vol_type == EXFAT) {
+ update_dir_checksum_with_entry_set(sb, es);
+ release_entry_set(es);
+ }
+
+#ifdef CONFIG_EXFAT_DELAYED_SYNC
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+#endif
+
+err_out:
+ /* set the size of written bytes */
+ if (wcount)
+ *wcount = write_bytes;
+
+ if (num_alloced == 0)
+ ret = FFS_FULL;
+
+ else if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size)
+{
+ s32 num_clusters;
+ u32 last_clu = CLUSTER_32(0);
+ int ret = 0;
+ sector_t sector = 0;
+ struct chain_t clu;
+ struct timestamp_t tm;
+ struct dentry_t *ep, *ep2;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+ struct entry_set_cache_t *es = NULL;
+
+ pr_debug("%s entered (inode %p size %llu)\n", __func__, inode,
+ new_size);
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ /* check if the given file ID is opened */
+ if (fid->type != TYPE_FILE) {
+ ret = FFS_PERMISSIONERR;
+ goto out;
+ }
+
+ if (fid->size != old_size) {
+ pr_err("[EXFAT] truncate : can't skip it because of size-mismatch(old:%lld->fid:%lld).\n",
+ old_size, fid->size);
+ }
+
+ if (old_size <= new_size) {
+ ret = FFS_SUCCESS;
+ goto out;
+ }
+
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ clu.dir = fid->start_clu;
+ clu.size = (s32)((old_size - 1) >> p_fs->cluster_size_bits) + 1;
+ clu.flags = fid->flags;
+
+ if (new_size > 0) {
+ num_clusters = (s32)((new_size - 1) >>
+ p_fs->cluster_size_bits) + 1;
+
+ if (clu.flags == 0x03) {
+ clu.dir += num_clusters;
+ } else {
+ while (num_clusters > 0) {
+ last_clu = clu.dir;
+ if (FAT_read(sb, clu.dir, &clu.dir) == -1) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ num_clusters--;
+ }
+ }
+
+ clu.size -= num_clusters;
+ }
+
+ fid->size = new_size;
+ fid->attr |= ATTR_ARCHIVE;
+ if (new_size == 0) {
+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
+ fid->start_clu = CLUSTER_32(~0);
+ }
+
+ /* (1) update the directory entry */
+ if (p_fs->vol_type == EXFAT) {
+ es = get_entry_set_in_dir(sb, &fid->dir, fid->entry,
+ ES_ALL_ENTRIES, &ep);
+ if (!es) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ ep2 = ep + 1;
+ } else {
+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ ep2 = ep;
+ }
+
+ p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY);
+ p_fs->fs_func->set_entry_attr(ep, fid->attr);
+
+ p_fs->fs_func->set_entry_size(ep2, new_size);
+ if (new_size == 0) {
+ p_fs->fs_func->set_entry_flag(ep2, 0x01);
+ p_fs->fs_func->set_entry_clu0(ep2, CLUSTER_32(0));
+ }
+
+ if (p_fs->vol_type != EXFAT) {
+ buf_modify(sb, sector);
+ } else {
+ update_dir_checksum_with_entry_set(sb, es);
+ release_entry_set(es);
+ }
+
+ /* (2) cut off from the FAT chain */
+ if (last_clu != CLUSTER_32(0)) {
+ if (fid->flags == 0x01)
+ FAT_write(sb, last_clu, CLUSTER_32(~0));
+ }
+
+ /* (3) free the clusters */
+ p_fs->fs_func->free_cluster(sb, &clu, 0);
+
+ /* hint information */
+ fid->hint_last_off = -1;
+ if (fid->rwoffset > fid->size)
+ fid->rwoffset = fid->size;
+
+#ifdef CONFIG_EXFAT_DELAYED_SYNC
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+#endif
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ pr_debug("%s exited (%d)\n", __func__, ret);
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+static void update_parent_info(struct file_id_t *fid,
+ struct inode *parent_inode)
+{
+ struct fs_info_t *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info);
+ struct file_id_t *parent_fid = &(EXFAT_I(parent_inode)->fid);
+
+ if (unlikely((parent_fid->flags != fid->dir.flags) ||
+ (parent_fid->size !=
+ (fid->dir.size << p_fs->cluster_size_bits)) ||
+ (parent_fid->start_clu != fid->dir.dir))) {
+ fid->dir.dir = parent_fid->start_clu;
+ fid->dir.flags = parent_fid->flags;
+ fid->dir.size = ((parent_fid->size + (p_fs->cluster_size - 1))
+ >> p_fs->cluster_size_bits);
+ }
+}
+
+static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid,
+ struct inode *new_parent_inode, struct dentry *new_dentry)
+{
+ s32 ret;
+ s32 dentry;
+ struct chain_t olddir, newdir;
+ struct chain_t *p_dir = NULL;
+ struct uni_name_t uni_name;
+ struct dentry_t *ep;
+ struct super_block *sb = old_parent_inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ u8 *new_path = (u8 *)new_dentry->d_name.name;
+ struct inode *new_inode = new_dentry->d_inode;
+ int num_entries;
+ struct file_id_t *new_fid = NULL;
+ s32 new_entry = 0;
+
+ /* check the validity of the given file id */
+ if (!fid)
+ return FFS_INVALIDFID;
+
+ /* check the validity of pointer parameters */
+ if (!new_path || (*new_path == '\0'))
+ return FFS_ERROR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ update_parent_info(fid, old_parent_inode);
+
+ olddir.dir = fid->dir.dir;
+ olddir.size = fid->dir.size;
+ olddir.flags = fid->dir.flags;
+
+ dentry = fid->entry;
+
+ /* check if the old file is "." or ".." */
+ if (p_fs->vol_type != EXFAT) {
+ if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) {
+ ret = FFS_PERMISSIONERR;
+ goto out2;
+ }
+ }
+
+ ep = get_entry_in_dir(sb, &olddir, dentry, NULL);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out2;
+ }
+
+ if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) {
+ ret = FFS_PERMISSIONERR;
+ goto out2;
+ }
+
+ /* check whether new dir is existing directory and empty */
+ if (new_inode) {
+ u32 entry_type;
+
+ ret = FFS_MEDIAERR;
+ new_fid = &EXFAT_I(new_inode)->fid;
+
+ update_parent_info(new_fid, new_parent_inode);
+
+ p_dir = &(new_fid->dir);
+ new_entry = new_fid->entry;
+ ep = get_entry_in_dir(sb, p_dir, new_entry, NULL);
+ if (!ep)
+ goto out;
+
+ entry_type = p_fs->fs_func->get_entry_type(ep);
+
+ if (entry_type == TYPE_DIR) {
+ struct chain_t new_clu;
+
+ new_clu.dir = new_fid->start_clu;
+ new_clu.size = (s32)((new_fid->size - 1) >>
+ p_fs->cluster_size_bits) + 1;
+ new_clu.flags = new_fid->flags;
+
+ if (!is_dir_empty(sb, &new_clu)) {
+ ret = FFS_FILEEXIST;
+ goto out;
+ }
+ }
+ }
+
+ /* check the validity of directory name in the given new pathname */
+ ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name);
+ if (ret)
+ goto out2;
+
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ if (olddir.dir == newdir.dir)
+ ret = rename_file(new_parent_inode, &olddir, dentry, &uni_name,
+ fid);
+ else
+ ret = move_file(new_parent_inode, &olddir, dentry, &newdir,
+ &uni_name, fid);
+
+ if ((ret == FFS_SUCCESS) && new_inode) {
+ /* delete entries of new_dir */
+ ep = get_entry_in_dir(sb, p_dir, new_entry, NULL);
+ if (!ep)
+ goto out;
+
+ num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir,
+ new_entry, ep);
+ if (num_entries < 0)
+ goto out;
+ p_fs->fs_func->delete_dir_entry(sb, p_dir, new_entry, 0,
+ num_entries + 1);
+ }
+out:
+#ifdef CONFIG_EXFAT_DELAYED_SYNC
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+#endif
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+out2:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid)
+{
+ s32 dentry;
+ int ret = FFS_SUCCESS;
+ struct chain_t dir, clu_to_free;
+ struct dentry_t *ep;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ /* check the validity of the given file id */
+ if (!fid)
+ return FFS_INVALIDFID;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ dir.dir = fid->dir.dir;
+ dir.size = fid->dir.size;
+ dir.flags = fid->dir.flags;
+
+ dentry = fid->entry;
+
+ ep = get_entry_in_dir(sb, &dir, dentry, NULL);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+
+ if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) {
+ ret = FFS_PERMISSIONERR;
+ goto out;
+ }
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ /* (1) update the directory entry */
+ remove_file(inode, &dir, dentry);
+
+ clu_to_free.dir = fid->start_clu;
+ clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1;
+ clu_to_free.flags = fid->flags;
+
+ /* (2) free the clusters */
+ p_fs->fs_func->free_cluster(sb, &clu_to_free, 0);
+
+ fid->size = 0;
+ fid->start_clu = CLUSTER_32(~0);
+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
+
+#ifdef CONFIG_EXFAT_DELAYED_SYNC
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+#endif
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+#if 0
+/* Not currently wired up */
+static int ffsSetAttr(struct inode *inode, u32 attr)
+{
+ u32 type;
+ int ret = FFS_SUCCESS;
+ sector_t sector = 0;
+ struct dentry_t *ep;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+ u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
+ struct entry_set_cache_t *es = NULL;
+
+ if (fid->attr == attr) {
+ if (p_fs->dev_ejected)
+ return FFS_MEDIAERR;
+ return FFS_SUCCESS;
+ }
+
+ if (is_dir) {
+ if ((fid->dir.dir == p_fs->root_dir) &&
+ (fid->entry == -1)) {
+ if (p_fs->dev_ejected)
+ return FFS_MEDIAERR;
+ return FFS_SUCCESS;
+ }
+ }
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ /* get the directory entry of given file */
+ if (p_fs->vol_type == EXFAT) {
+ es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry,
+ ES_ALL_ENTRIES, &ep);
+ if (!es) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ } else {
+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ }
+
+ type = p_fs->fs_func->get_entry_type(ep);
+
+ if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) ||
+ ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) {
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+ else
+ ret = FFS_ERROR;
+
+ if (p_fs->vol_type == EXFAT)
+ release_entry_set(es);
+ goto out;
+ }
+
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ /* set the file attribute */
+ fid->attr = attr;
+ p_fs->fs_func->set_entry_attr(ep, attr);
+
+ if (p_fs->vol_type != EXFAT) {
+ buf_modify(sb, sector);
+ } else {
+ update_dir_checksum_with_entry_set(sb, es);
+ release_entry_set(es);
+ }
+
+#ifdef CONFIG_EXFAT_DELAYED_SYNC
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+#endif
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+#endif
+
+static int ffsReadStat(struct inode *inode, struct dir_entry_t *info)
+{
+ sector_t sector = 0;
+ s32 count;
+ int ret = FFS_SUCCESS;
+ struct chain_t dir;
+ struct uni_name_t uni_name;
+ struct timestamp_t tm;
+ struct dentry_t *ep, *ep2;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+ struct entry_set_cache_t *es = NULL;
+ u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
+
+ pr_debug("%s entered\n", __func__);
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ if (is_dir) {
+ if ((fid->dir.dir == p_fs->root_dir) &&
+ (fid->entry == -1)) {
+ info->Attr = ATTR_SUBDIR;
+ memset((char *)&info->CreateTimestamp, 0,
+ sizeof(struct date_time_t));
+ memset((char *)&info->ModifyTimestamp, 0,
+ sizeof(struct date_time_t));
+ memset((char *)&info->AccessTimestamp, 0,
+ sizeof(struct date_time_t));
+ strcpy(info->ShortName, ".");
+ strcpy(info->Name, ".");
+
+ dir.dir = p_fs->root_dir;
+ dir.flags = 0x01;
+
+ if (p_fs->root_dir == CLUSTER_32(0)) {
+ /* FAT16 root_dir */
+ info->Size = p_fs->dentries_in_root <<
+ DENTRY_SIZE_BITS;
+ } else {
+ info->Size = count_num_clusters(sb, &dir) <<
+ p_fs->cluster_size_bits;
+ }
+
+ count = count_dos_name_entries(sb, &dir, TYPE_DIR);
+ if (count < 0) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ info->NumSubdirs = count;
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ }
+
+ /* get the directory entry of given file or directory */
+ if (p_fs->vol_type == EXFAT) {
+ es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry,
+ ES_2_ENTRIES, &ep);
+ if (!es) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ ep2 = ep + 1;
+ } else {
+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ ep2 = ep;
+ buf_lock(sb, sector);
+ }
+
+ /* set FILE_INFO structure using the acquired struct dentry_t */
+ info->Attr = p_fs->fs_func->get_entry_attr(ep);
+
+ p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE);
+ info->CreateTimestamp.Year = tm.year;
+ info->CreateTimestamp.Month = tm.mon;
+ info->CreateTimestamp.Day = tm.day;
+ info->CreateTimestamp.Hour = tm.hour;
+ info->CreateTimestamp.Minute = tm.min;
+ info->CreateTimestamp.Second = tm.sec;
+ info->CreateTimestamp.MilliSecond = 0;
+
+ p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY);
+ info->ModifyTimestamp.Year = tm.year;
+ info->ModifyTimestamp.Month = tm.mon;
+ info->ModifyTimestamp.Day = tm.day;
+ info->ModifyTimestamp.Hour = tm.hour;
+ info->ModifyTimestamp.Minute = tm.min;
+ info->ModifyTimestamp.Second = tm.sec;
+ info->ModifyTimestamp.MilliSecond = 0;
+
+ memset((char *)&info->AccessTimestamp, 0, sizeof(struct date_time_t));
+
+ *(uni_name.name) = 0x0;
+ /* XXX this is very bad for exfat cuz name is already included in es.
+ * API should be revised
+ */
+ p_fs->fs_func->get_uni_name_from_ext_entry(sb, &(fid->dir), fid->entry,
+ uni_name.name);
+ if (*uni_name.name == 0x0 && p_fs->vol_type != EXFAT)
+ get_uni_name_from_dos_entry(sb, (struct dos_dentry_t *)ep,
+ &uni_name, 0x1);
+ nls_uniname_to_cstring(sb, info->Name, &uni_name);
+
+ if (p_fs->vol_type == EXFAT) {
+ info->NumSubdirs = 2;
+ } else {
+ buf_unlock(sb, sector);
+ get_uni_name_from_dos_entry(sb, (struct dos_dentry_t *)ep,
+ &uni_name, 0x0);
+ nls_uniname_to_cstring(sb, info->ShortName, &uni_name);
+ info->NumSubdirs = 0;
+ }
+
+ info->Size = p_fs->fs_func->get_entry_size(ep2);
+
+ if (p_fs->vol_type == EXFAT)
+ release_entry_set(es);
+
+ if (is_dir) {
+ dir.dir = fid->start_clu;
+ dir.flags = 0x01;
+
+ if (info->Size == 0)
+ info->Size = (u64)count_num_clusters(sb, &dir) <<
+ p_fs->cluster_size_bits;
+
+ count = count_dos_name_entries(sb, &dir, TYPE_DIR);
+ if (count < 0) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ info->NumSubdirs += count;
+ }
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ pr_debug("%s exited successfully\n", __func__);
+ return ret;
+}
+
+static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info)
+{
+ sector_t sector = 0;
+ int ret = FFS_SUCCESS;
+ struct timestamp_t tm;
+ struct dentry_t *ep, *ep2;
+ struct entry_set_cache_t *es = NULL;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+ u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
+
+ pr_debug("%s entered (inode %p info %p\n", __func__, inode, info);
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ if (is_dir) {
+ if ((fid->dir.dir == p_fs->root_dir) &&
+ (fid->entry == -1)) {
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+ ret = FFS_SUCCESS;
+ goto out;
+ }
+ }
+
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ /* get the directory entry of given file or directory */
+ if (p_fs->vol_type == EXFAT) {
+ es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry,
+ ES_ALL_ENTRIES, &ep);
+ if (!es) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ ep2 = ep + 1;
+ } else {
+ /* for other than exfat */
+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ ep2 = ep;
+ }
+
+ p_fs->fs_func->set_entry_attr(ep, info->Attr);
+
+ /* set FILE_INFO structure using the acquired struct dentry_t */
+ tm.sec = info->CreateTimestamp.Second;
+ tm.min = info->CreateTimestamp.Minute;
+ tm.hour = info->CreateTimestamp.Hour;
+ tm.day = info->CreateTimestamp.Day;
+ tm.mon = info->CreateTimestamp.Month;
+ tm.year = info->CreateTimestamp.Year;
+ p_fs->fs_func->set_entry_time(ep, &tm, TM_CREATE);
+
+ tm.sec = info->ModifyTimestamp.Second;
+ tm.min = info->ModifyTimestamp.Minute;
+ tm.hour = info->ModifyTimestamp.Hour;
+ tm.day = info->ModifyTimestamp.Day;
+ tm.mon = info->ModifyTimestamp.Month;
+ tm.year = info->ModifyTimestamp.Year;
+ p_fs->fs_func->set_entry_time(ep, &tm, TM_MODIFY);
+
+ p_fs->fs_func->set_entry_size(ep2, info->Size);
+
+ if (p_fs->vol_type != EXFAT) {
+ buf_modify(sb, sector);
+ } else {
+ update_dir_checksum_with_entry_set(sb, es);
+ release_entry_set(es);
+ }
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ pr_debug("%s exited (%d)\n", __func__, ret);
+
+ return ret;
+}
+
+static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu)
+{
+ s32 num_clusters, num_alloced;
+ bool modified = false;
+ u32 last_clu;
+ int ret = FFS_SUCCESS;
+ sector_t sector = 0;
+ struct chain_t new_clu;
+ struct dentry_t *ep;
+ struct entry_set_cache_t *es = NULL;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+
+ /* check the validity of pointer parameters */
+ if (!clu)
+ return FFS_ERROR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits;
+
+ if (EXFAT_I(inode)->mmu_private == 0)
+ num_clusters = 0;
+ else
+ num_clusters = (s32)((EXFAT_I(inode)->mmu_private - 1) >>
+ p_fs->cluster_size_bits) + 1;
+
+ *clu = last_clu = fid->start_clu;
+
+ if (fid->flags == 0x03) {
+ if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) {
+ last_clu += clu_offset - 1;
+
+ if (clu_offset == num_clusters)
+ *clu = CLUSTER_32(~0);
+ else
+ *clu += clu_offset;
+ }
+ } else {
+ /* hint information */
+ if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
+ (clu_offset >= fid->hint_last_off)) {
+ clu_offset -= fid->hint_last_off;
+ *clu = fid->hint_last_clu;
+ }
+
+ while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) {
+ last_clu = *clu;
+ if (FAT_read(sb, *clu, clu) == -1) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ clu_offset--;
+ }
+ }
+
+ if (*clu == CLUSTER_32(~0)) {
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) :
+ last_clu + 1;
+ new_clu.size = 0;
+ new_clu.flags = fid->flags;
+
+ /* (1) allocate a cluster */
+ num_alloced = p_fs->fs_func->alloc_cluster(sb, 1, &new_clu);
+ if (num_alloced < 0) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ } else if (num_alloced == 0) {
+ ret = FFS_FULL;
+ goto out;
+ }
+
+ /* (2) append to the FAT chain */
+ if (last_clu == CLUSTER_32(~0)) {
+ if (new_clu.flags == 0x01)
+ fid->flags = 0x01;
+ fid->start_clu = new_clu.dir;
+ modified = true;
+ } else {
+ if (new_clu.flags != fid->flags) {
+ exfat_chain_cont_cluster(sb, fid->start_clu,
+ num_clusters);
+ fid->flags = 0x01;
+ modified = true;
+ }
+ if (new_clu.flags == 0x01)
+ FAT_write(sb, last_clu, new_clu.dir);
+ }
+
+ num_clusters += num_alloced;
+ *clu = new_clu.dir;
+
+ if (p_fs->vol_type == EXFAT) {
+ es = get_entry_set_in_dir(sb, &fid->dir, fid->entry,
+ ES_ALL_ENTRIES, &ep);
+ if (!es) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ /* get stream entry */
+ ep++;
+ }
+
+ /* (3) update directory entry */
+ if (modified) {
+ if (p_fs->vol_type != EXFAT) {
+ ep = get_entry_in_dir(sb, &(fid->dir),
+ fid->entry, &sector);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ }
+
+ if (p_fs->fs_func->get_entry_flag(ep) != fid->flags)
+ p_fs->fs_func->set_entry_flag(ep, fid->flags);
+
+ if (p_fs->fs_func->get_entry_clu0(ep) != fid->start_clu)
+ p_fs->fs_func->set_entry_clu0(ep,
+ fid->start_clu);
+
+ if (p_fs->vol_type != EXFAT)
+ buf_modify(sb, sector);
+ }
+
+ if (p_fs->vol_type == EXFAT) {
+ update_dir_checksum_with_entry_set(sb, es);
+ release_entry_set(es);
+ }
+
+ /* add number of new blocks to inode */
+ inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9);
+ }
+
+ /* hint information */
+ fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits);
+ fid->hint_last_clu = *clu;
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------*/
+/* Directory Operation Functions */
+/*----------------------------------------------------------------------*/
+
+static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid)
+{
+ int ret = FFS_SUCCESS;
+ struct chain_t dir;
+ struct uni_name_t uni_name;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ pr_debug("%s entered\n", __func__);
+
+ /* check the validity of pointer parameters */
+ if (!fid || !path || (*path == '\0'))
+ return FFS_ERROR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ /* check the validity of directory name in the given old pathname */
+ ret = resolve_path(inode, path, &dir, &uni_name);
+ if (ret)
+ goto out;
+
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ ret = create_dir(inode, &dir, &uni_name, fid);
+
+#ifdef CONFIG_EXFAT_DELAYED_SYNC
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+#endif
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry)
+{
+ int i, dentry, clu_offset;
+ int ret = FFS_SUCCESS;
+ s32 dentries_per_clu, dentries_per_clu_bits = 0;
+ u32 type;
+ sector_t sector;
+ struct chain_t dir, clu;
+ struct uni_name_t uni_name;
+ struct timestamp_t tm;
+ struct dentry_t *ep;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct fs_func *fs_func = p_fs->fs_func;
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+
+ /* check the validity of pointer parameters */
+ if (!dir_entry)
+ return FFS_ERROR;
+
+ /* check if the given file ID is opened */
+ if (fid->type != TYPE_DIR)
+ return FFS_PERMISSIONERR;
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ if (fid->entry == -1) {
+ dir.dir = p_fs->root_dir;
+ dir.flags = 0x01;
+ } else {
+ dir.dir = fid->start_clu;
+ dir.size = (s32)(fid->size >> p_fs->cluster_size_bits);
+ dir.flags = fid->flags;
+ }
+
+ dentry = (s32)fid->rwoffset;
+
+ if (dir.dir == CLUSTER_32(0)) {
+ /* FAT16 root_dir */
+ dentries_per_clu = p_fs->dentries_in_root;
+
+ if (dentry == dentries_per_clu) {
+ clu.dir = CLUSTER_32(~0);
+ } else {
+ clu.dir = dir.dir;
+ clu.size = dir.size;
+ clu.flags = dir.flags;
+ }
+ } else {
+ dentries_per_clu = p_fs->dentries_per_clu;
+ dentries_per_clu_bits = ilog2(dentries_per_clu);
+
+ clu_offset = dentry >> dentries_per_clu_bits;
+ clu.dir = dir.dir;
+ clu.size = dir.size;
+ clu.flags = dir.flags;
+
+ if (clu.flags == 0x03) {
+ clu.dir += clu_offset;
+ clu.size -= clu_offset;
+ } else {
+ /* hint_information */
+ if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
+ (clu_offset >= fid->hint_last_off)) {
+ clu_offset -= fid->hint_last_off;
+ clu.dir = fid->hint_last_clu;
+ }
+
+ while (clu_offset > 0) {
+ /* clu.dir = FAT_read(sb, clu.dir); */
+ if (FAT_read(sb, clu.dir, &clu.dir) == -1) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ clu_offset--;
+ }
+ }
+ }
+
+ while (clu.dir != CLUSTER_32(~0)) {
+ if (p_fs->dev_ejected)
+ break;
+
+ if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */
+ i = dentry % dentries_per_clu;
+ else
+ i = dentry & (dentries_per_clu - 1);
+
+ for ( ; i < dentries_per_clu; i++, dentry++) {
+ ep = get_entry_in_dir(sb, &clu, i, &sector);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ type = fs_func->get_entry_type(ep);
+
+ if (type == TYPE_UNUSED)
+ break;
+
+ if ((type != TYPE_FILE) && (type != TYPE_DIR))
+ continue;
+
+ buf_lock(sb, sector);
+ dir_entry->Attr = fs_func->get_entry_attr(ep);
+
+ fs_func->get_entry_time(ep, &tm, TM_CREATE);
+ dir_entry->CreateTimestamp.Year = tm.year;
+ dir_entry->CreateTimestamp.Month = tm.mon;
+ dir_entry->CreateTimestamp.Day = tm.day;
+ dir_entry->CreateTimestamp.Hour = tm.hour;
+ dir_entry->CreateTimestamp.Minute = tm.min;
+ dir_entry->CreateTimestamp.Second = tm.sec;
+ dir_entry->CreateTimestamp.MilliSecond = 0;
+
+ fs_func->get_entry_time(ep, &tm, TM_MODIFY);
+ dir_entry->ModifyTimestamp.Year = tm.year;
+ dir_entry->ModifyTimestamp.Month = tm.mon;
+ dir_entry->ModifyTimestamp.Day = tm.day;
+ dir_entry->ModifyTimestamp.Hour = tm.hour;
+ dir_entry->ModifyTimestamp.Minute = tm.min;
+ dir_entry->ModifyTimestamp.Second = tm.sec;
+ dir_entry->ModifyTimestamp.MilliSecond = 0;
+
+ memset((char *)&dir_entry->AccessTimestamp, 0,
+ sizeof(struct date_time_t));
+
+ *(uni_name.name) = 0x0;
+ fs_func->get_uni_name_from_ext_entry(sb, &dir, dentry,
+ uni_name.name);
+ if (*uni_name.name == 0x0 && p_fs->vol_type != EXFAT)
+ get_uni_name_from_dos_entry(sb,
+ (struct dos_dentry_t *)ep,
+ &uni_name, 0x1);
+ nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name);
+ buf_unlock(sb, sector);
+
+ if (p_fs->vol_type == EXFAT) {
+ ep = get_entry_in_dir(sb, &clu, i + 1, NULL);
+ if (!ep) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ } else {
+ get_uni_name_from_dos_entry(sb,
+ (struct dos_dentry_t *)ep,
+ &uni_name, 0x0);
+ nls_uniname_to_cstring(sb, dir_entry->ShortName,
+ &uni_name);
+ }
+
+ dir_entry->Size = fs_func->get_entry_size(ep);
+
+ /* hint information */
+ if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */
+ } else {
+ fid->hint_last_off = dentry >>
+ dentries_per_clu_bits;
+ fid->hint_last_clu = clu.dir;
+ }
+
+ fid->rwoffset = (s64)(++dentry);
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+
+ if (dir.dir == CLUSTER_32(0))
+ break; /* FAT16 root_dir */
+
+ if (clu.flags == 0x03) {
+ if ((--clu.size) > 0)
+ clu.dir++;
+ else
+ clu.dir = CLUSTER_32(~0);
+ } else {
+ /* clu.dir = FAT_read(sb, clu.dir); */
+ if (FAT_read(sb, clu.dir, &clu.dir) == -1) {
+ ret = FFS_MEDIAERR;
+ goto out;
+ }
+ }
+ }
+
+ *(dir_entry->Name) = '\0';
+
+ fid->rwoffset = (s64)(++dentry);
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid)
+{
+ s32 dentry;
+ int ret = FFS_SUCCESS;
+ struct chain_t dir, clu_to_free;
+ struct super_block *sb = inode->i_sb;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ /* check the validity of the given file id */
+ if (!fid)
+ return FFS_INVALIDFID;
+
+ dir.dir = fid->dir.dir;
+ dir.size = fid->dir.size;
+ dir.flags = fid->dir.flags;
+
+ dentry = fid->entry;
+
+ /* check if the file is "." or ".." */
+ if (p_fs->vol_type != EXFAT) {
+ if ((dir.dir != p_fs->root_dir) && (dentry < 2))
+ return FFS_PERMISSIONERR;
+ }
+
+ /* acquire the lock for file system critical section */
+ down(&p_fs->v_sem);
+
+ clu_to_free.dir = fid->start_clu;
+ clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1;
+ clu_to_free.flags = fid->flags;
+
+ if (!is_dir_empty(sb, &clu_to_free)) {
+ ret = FFS_FILEEXIST;
+ goto out;
+ }
+
+ fs_set_vol_flags(sb, VOL_DIRTY);
+
+ /* (1) update the directory entry */
+ remove_file(inode, &dir, dentry);
+
+ /* (2) free the clusters */
+ p_fs->fs_func->free_cluster(sb, &clu_to_free, 1);
+
+ fid->size = 0;
+ fid->start_clu = CLUSTER_32(~0);
+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
+
+#ifdef CONFIG_EXFAT_DELAYED_SYNC
+ fs_sync(sb, false);
+ fs_set_vol_flags(sb, VOL_CLEAN);
+#endif
+
+ if (p_fs->dev_ejected)
+ ret = FFS_MEDIAERR;
+
+out:
+ /* release the lock for file system critical section */
+ up(&p_fs->v_sem);
+
+ return ret;
+}
+
+/*======================================================================*/
+/* Directory Entry Operations */
+/*======================================================================*/
+
+static int exfat_readdir(struct file *filp, struct dir_context *ctx)
+{
+ struct inode *inode = file_inode(filp);
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct fs_info_t *p_fs = &(sbi->fs_info);
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct dir_entry_t de;
+ unsigned long inum;
+ loff_t cpos;
+ int err = 0;
+
+ __lock_super(sb);
+
+ cpos = ctx->pos;
+ /* Fake . and .. for the root directory. */
+ if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) {
+ while (cpos < 2) {
+ if (inode->i_ino == EXFAT_ROOT_INO)
+ inum = EXFAT_ROOT_INO;
+ else if (cpos == 0)
+ inum = inode->i_ino;
+ else /* (cpos == 1) */
+ inum = parent_ino(filp->f_path.dentry);
+
+ if (!dir_emit_dots(filp, ctx))
+ goto out;
+ cpos++;
+ ctx->pos++;
+ }
+ if (cpos == 2)
+ cpos = 0;
+ }
+ if (cpos & (DENTRY_SIZE - 1)) {
+ err = -ENOENT;
+ goto out;
+ }
+
+get_new:
+ EXFAT_I(inode)->fid.size = i_size_read(inode);
+ EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS;
+
+ err = ffsReadDir(inode, &de);
+ if (err) {
+ /* at least we tried to read a sector
+ * move cpos to next sector position (should be aligned)
+ */
+ if (err == FFS_MEDIAERR) {
+ cpos += 1 << p_bd->sector_size_bits;
+ cpos &= ~((1 << p_bd->sector_size_bits) - 1);
+ }
+
+ err = -EIO;
+ goto end_of_dir;
+ }
+
+ cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS;
+
+ if (!de.Name[0])
+ goto end_of_dir;
+
+ if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) {
+ inum = inode->i_ino;
+ } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) {
+ inum = parent_ino(filp->f_path.dentry);
+ } else {
+ loff_t i_pos = ((loff_t)EXFAT_I(inode)->fid.start_clu << 32) |
+ ((EXFAT_I(inode)->fid.rwoffset - 1) & 0xffffffff);
+ struct inode *tmp = exfat_iget(sb, i_pos);
+
+ if (tmp) {
+ inum = tmp->i_ino;
+ iput(tmp);
+ } else {
+ inum = iunique(sb, EXFAT_ROOT_INO);
+ }
+ }
+
+ if (!dir_emit(ctx, de.Name, strlen(de.Name), inum,
+ (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG))
+ goto out;
+
+ ctx->pos = cpos;
+ goto get_new;
+
+end_of_dir:
+ ctx->pos = cpos;
+out:
+ __unlock_super(sb);
+ return err;
+}
+
+static int exfat_ioctl_volume_id(struct inode *dir)
+{
+ struct super_block *sb = dir->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct fs_info_t *p_fs = &(sbi->fs_info);
+
+ return p_fs->vol_id;
+}
+
+static long exfat_generic_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+struct inode *inode = filp->f_path.dentry->d_inode;
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ unsigned int flags;
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+ switch (cmd) {
+ case EXFAT_IOCTL_GET_VOLUME_ID:
+ return exfat_ioctl_volume_id(inode);
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ case EXFAT_IOC_GET_DEBUGFLAGS: {
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ flags = sbi->debug_flags;
+ return put_user(flags, (int __user *)arg);
+ }
+ case EXFAT_IOC_SET_DEBUGFLAGS: {
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (get_user(flags, (int __user *)arg))
+ return -EFAULT;
+
+ __lock_super(sb);
+ sbi->debug_flags = flags;
+ __unlock_super(sb);
+
+ return 0;
+ }
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+ default:
+ return -ENOTTY; /* Inappropriate ioctl for device */
+ }
+}
+
+static const struct file_operations exfat_dir_operations = {
+ .llseek = generic_file_llseek,
+ .read = generic_read_dir,
+ .iterate = exfat_readdir,
+ .unlocked_ioctl = exfat_generic_ioctl,
+ .fsync = generic_file_fsync,
+};
+
+static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ bool excl)
+{
+ struct super_block *sb = dir->i_sb;
+ struct inode *inode;
+ struct file_id_t fid;
+ loff_t i_pos;
+ int err;
+
+ __lock_super(sb);
+
+ pr_debug("%s entered\n", __func__);
+
+ err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_REGULAR, &fid);
+ if (err) {
+ if (err == FFS_INVALIDPATH)
+ err = -EINVAL;
+ else if (err == FFS_FILEEXIST)
+ err = -EEXIST;
+ else if (err == FFS_FULL)
+ err = -ENOSPC;
+ else if (err == FFS_NAMETOOLONG)
+ err = -ENAMETOOLONG;
+ else
+ err = -EIO;
+ goto out;
+ }
+ INC_IVERSION(dir);
+ dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir);
+ if (IS_DIRSYNC(dir))
+ (void)exfat_sync_inode(dir);
+ else
+ mark_inode_dirty(dir);
+
+ i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff);
+
+ inode = exfat_build_inode(sb, &fid, i_pos);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto out;
+ }
+ INC_IVERSION(inode);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+ /*
+ * timestamp is already written, so mark_inode_dirty() is unnecessary.
+ */
+
+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
+ d_instantiate(dentry, inode);
+
+out:
+ __unlock_super(sb);
+ pr_debug("%s exited\n", __func__);
+ return err;
+}
+
+static int exfat_find(struct inode *dir, struct qstr *qname,
+ struct file_id_t *fid)
+{
+ int err;
+
+ if (qname->len == 0)
+ return -ENOENT;
+
+ err = ffsLookupFile(dir, (u8 *)qname->name, fid);
+ if (err)
+ return -ENOENT;
+
+ return 0;
+}
+
+static int exfat_d_anon_disconn(struct dentry *dentry)
+{
+ return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED);
+}
+
+static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ struct super_block *sb = dir->i_sb;
+ struct inode *inode;
+ struct dentry *alias;
+ int err;
+ struct file_id_t fid;
+ loff_t i_pos;
+ u64 ret;
+ mode_t i_mode;
+
+ __lock_super(sb);
+ pr_debug("%s entered\n", __func__);
+ err = exfat_find(dir, &dentry->d_name, &fid);
+ if (err) {
+ if (err == -ENOENT) {
+ inode = NULL;
+ goto out;
+ }
+ goto error;
+ }
+
+ i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff);
+ inode = exfat_build_inode(sb, &fid, i_pos);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto error;
+ }
+
+ i_mode = inode->i_mode;
+ if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) {
+ EXFAT_I(inode)->target = kmalloc(i_size_read(inode) + 1,
+ GFP_KERNEL);
+ if (!EXFAT_I(inode)->target) {
+ err = -ENOMEM;
+ goto error;
+ }
+ ffsReadFile(dir, &fid, EXFAT_I(inode)->target,
+ i_size_read(inode), &ret);
+ *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0';
+ }
+
+ alias = d_find_alias(inode);
+ if (alias && !exfat_d_anon_disconn(alias)) {
+ BUG_ON(d_unhashed(alias));
+ if (!S_ISDIR(i_mode))
+ d_move(alias, dentry);
+ iput(inode);
+ __unlock_super(sb);
+ pr_debug("%s exited 1\n", __func__);
+ return alias;
+ }
+ dput(alias);
+out:
+ __unlock_super(sb);
+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
+ dentry = d_splice_alias(inode, dentry);
+ if (dentry)
+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
+ pr_debug("%s exited 2\n", __func__);
+ return dentry;
+
+error:
+ __unlock_super(sb);
+ pr_debug("%s exited 3\n", __func__);
+ return ERR_PTR(err);
+}
+
+static inline unsigned long exfat_hash(loff_t i_pos)
+{
+ return hash_32(i_pos, EXFAT_HASH_BITS);
+}
+
+static void exfat_attach(struct inode *inode, loff_t i_pos)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
+ struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos);
+
+ spin_lock(&sbi->inode_hash_lock);
+ EXFAT_I(inode)->i_pos = i_pos;
+ hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head);
+ spin_unlock(&sbi->inode_hash_lock);
+}
+
+static void exfat_detach(struct inode *inode)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
+
+ spin_lock(&sbi->inode_hash_lock);
+ hlist_del_init(&EXFAT_I(inode)->i_hash_fat);
+ EXFAT_I(inode)->i_pos = 0;
+ spin_unlock(&sbi->inode_hash_lock);
+}
+
+static int exfat_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ struct super_block *sb = dir->i_sb;
+ int err;
+
+ __lock_super(sb);
+
+ pr_debug("%s entered\n", __func__);
+
+ EXFAT_I(inode)->fid.size = i_size_read(inode);
+
+ err = ffsRemoveFile(dir, &(EXFAT_I(inode)->fid));
+ if (err) {
+ if (err == FFS_PERMISSIONERR)
+ err = -EPERM;
+ else
+ err = -EIO;
+ goto out;
+ }
+ INC_IVERSION(dir);
+ dir->i_mtime = dir->i_atime = current_time(dir);
+ if (IS_DIRSYNC(dir))
+ (void)exfat_sync_inode(dir);
+ else
+ mark_inode_dirty(dir);
+
+ clear_nlink(inode);
+ inode->i_mtime = inode->i_atime = current_time(inode);
+ exfat_detach(inode);
+ remove_inode_hash(inode);
+
+out:
+ __unlock_super(sb);
+ pr_debug("%s exited\n", __func__);
+ return err;
+}
+
+static int exfat_symlink(struct inode *dir, struct dentry *dentry,
+ const char *target)
+{
+ struct super_block *sb = dir->i_sb;
+ struct inode *inode;
+ struct file_id_t fid;
+ loff_t i_pos;
+ int err;
+ u64 len = (u64)strlen(target);
+ u64 ret;
+
+ __lock_super(sb);
+
+ pr_debug("%s entered\n", __func__);
+
+ err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_SYMLINK, &fid);
+ if (err) {
+ if (err == FFS_INVALIDPATH)
+ err = -EINVAL;
+ else if (err == FFS_FILEEXIST)
+ err = -EEXIST;
+ else if (err == FFS_FULL)
+ err = -ENOSPC;
+ else
+ err = -EIO;
+ goto out;
+ }
+
+ err = ffsWriteFile(dir, &fid, (char *)target, len, &ret);
+
+ if (err) {
+ ffsRemoveFile(dir, &fid);
+
+ if (err == FFS_FULL)
+ err = -ENOSPC;
+ else
+ err = -EIO;
+ goto out;
+ }
+
+ INC_IVERSION(dir);
+ dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir);
+ if (IS_DIRSYNC(dir))
+ (void)exfat_sync_inode(dir);
+ else
+ mark_inode_dirty(dir);
+
+ i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff);
+
+ inode = exfat_build_inode(sb, &fid, i_pos);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto out;
+ }
+ INC_IVERSION(inode);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
+ EXFAT_I(inode)->target = kmemdup(target, len + 1, GFP_KERNEL);
+ if (!EXFAT_I(inode)->target) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
+ d_instantiate(dentry, inode);
+
+out:
+ __unlock_super(sb);
+ pr_debug("%s exited\n", __func__);
+ return err;
+}
+
+static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+ struct super_block *sb = dir->i_sb;
+ struct inode *inode;
+ struct file_id_t fid;
+ loff_t i_pos;
+ int err;
+
+ __lock_super(sb);
+
+ pr_debug("%s entered\n", __func__);
+
+ err = ffsCreateDir(dir, (u8 *)dentry->d_name.name, &fid);
+ if (err) {
+ if (err == FFS_INVALIDPATH)
+ err = -EINVAL;
+ else if (err == FFS_FILEEXIST)
+ err = -EEXIST;
+ else if (err == FFS_FULL)
+ err = -ENOSPC;
+ else if (err == FFS_NAMETOOLONG)
+ err = -ENAMETOOLONG;
+ else
+ err = -EIO;
+ goto out;
+ }
+ INC_IVERSION(dir);
+ dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir);
+ if (IS_DIRSYNC(dir))
+ (void)exfat_sync_inode(dir);
+ else
+ mark_inode_dirty(dir);
+ inc_nlink(dir);
+
+ i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff);
+
+ inode = exfat_build_inode(sb, &fid, i_pos);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto out;
+ }
+ INC_IVERSION(inode);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
+ d_instantiate(dentry, inode);
+
+out:
+ __unlock_super(sb);
+ pr_debug("%s exited\n", __func__);
+ return err;
+}
+
+static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ struct super_block *sb = dir->i_sb;
+ int err;
+
+ __lock_super(sb);
+
+ pr_debug("%s entered\n", __func__);
+
+ EXFAT_I(inode)->fid.size = i_size_read(inode);
+
+ err = ffsRemoveDir(dir, &(EXFAT_I(inode)->fid));
+ if (err) {
+ if (err == FFS_INVALIDPATH)
+ err = -EINVAL;
+ else if (err == FFS_FILEEXIST)
+ err = -ENOTEMPTY;
+ else if (err == FFS_NOTFOUND)
+ err = -ENOENT;
+ else if (err == FFS_DIRBUSY)
+ err = -EBUSY;
+ else
+ err = -EIO;
+ goto out;
+ }
+ INC_IVERSION(dir);
+ dir->i_mtime = dir->i_atime = current_time(dir);
+ if (IS_DIRSYNC(dir))
+ (void)exfat_sync_inode(dir);
+ else
+ mark_inode_dirty(dir);
+ drop_nlink(dir);
+
+ clear_nlink(inode);
+ inode->i_mtime = inode->i_atime = current_time(inode);
+ exfat_detach(inode);
+ remove_inode_hash(inode);
+
+out:
+ __unlock_super(sb);
+ pr_debug("%s exited\n", __func__);
+ return err;
+}
+
+static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
+{
+ struct inode *old_inode, *new_inode;
+ struct super_block *sb = old_dir->i_sb;
+ loff_t i_pos;
+ int err;
+
+ if (flags)
+ return -EINVAL;
+
+ __lock_super(sb);
+
+ pr_debug("%s entered\n", __func__);
+
+ old_inode = old_dentry->d_inode;
+ new_inode = new_dentry->d_inode;
+
+ EXFAT_I(old_inode)->fid.size = i_size_read(old_inode);
+
+ err = ffsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir,
+ new_dentry);
+ if (err) {
+ if (err == FFS_PERMISSIONERR)
+ err = -EPERM;
+ else if (err == FFS_INVALIDPATH)
+ err = -EINVAL;
+ else if (err == FFS_FILEEXIST)
+ err = -EEXIST;
+ else if (err == FFS_NOTFOUND)
+ err = -ENOENT;
+ else if (err == FFS_FULL)
+ err = -ENOSPC;
+ else
+ err = -EIO;
+ goto out;
+ }
+ INC_IVERSION(new_dir);
+ new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
+ current_time(new_dir);
+ if (IS_DIRSYNC(new_dir))
+ (void)exfat_sync_inode(new_dir);
+ else
+ mark_inode_dirty(new_dir);
+
+ i_pos = ((loff_t)EXFAT_I(old_inode)->fid.dir.dir << 32) |
+ (EXFAT_I(old_inode)->fid.entry & 0xffffffff);
+
+ exfat_detach(old_inode);
+ exfat_attach(old_inode, i_pos);
+ if (IS_DIRSYNC(new_dir))
+ (void)exfat_sync_inode(old_inode);
+ else
+ mark_inode_dirty(old_inode);
+
+ if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) {
+ drop_nlink(old_dir);
+ if (!new_inode)
+ inc_nlink(new_dir);
+ }
+ INC_IVERSION(old_dir);
+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
+ if (IS_DIRSYNC(old_dir))
+ (void)exfat_sync_inode(old_dir);
+ else
+ mark_inode_dirty(old_dir);
+
+ if (new_inode) {
+ exfat_detach(new_inode);
+ drop_nlink(new_inode);
+ if (S_ISDIR(new_inode->i_mode))
+ drop_nlink(new_inode);
+ new_inode->i_ctime = current_time(new_inode);
+ }
+
+out:
+ __unlock_super(sb);
+ pr_debug("%s exited\n", __func__);
+ return err;
+}
+
+static int exfat_cont_expand(struct inode *inode, loff_t size)
+{
+ struct address_space *mapping = inode->i_mapping;
+ loff_t start = i_size_read(inode), count = size - i_size_read(inode);
+ int err, err2;
+
+ err = generic_cont_expand_simple(inode, size);
+ if (err != 0)
+ return err;
+
+ inode->i_ctime = inode->i_mtime = current_time(inode);
+ mark_inode_dirty(inode);
+
+ if (IS_SYNC(inode)) {
+ err = filemap_fdatawrite_range(mapping, start,
+ start + count - 1);
+ err2 = sync_mapping_buffers(mapping);
+ err = (err) ? (err) : (err2);
+ err2 = write_inode_now(inode, 1);
+ err = (err) ? (err) : (err2);
+ if (!err)
+ err = filemap_fdatawait_range(mapping, start,
+ start + count - 1);
+ }
+ return err;
+}
+
+static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode)
+{
+ mode_t allow_utime = sbi->options.allow_utime;
+
+ if (!uid_eq(current_fsuid(), inode->i_uid)) {
+ if (in_group_p(inode->i_gid))
+ allow_utime >>= 3;
+ if (allow_utime & MAY_WRITE)
+ return 1;
+ }
+
+ /* use a default check */
+ return 0;
+}
+
+static int exfat_sanitize_mode(const struct exfat_sb_info *sbi,
+ struct inode *inode, umode_t *mode_ptr)
+{
+ mode_t i_mode, mask, perm;
+
+ i_mode = inode->i_mode;
+
+ if (S_ISREG(i_mode) || S_ISLNK(i_mode))
+ mask = sbi->options.fs_fmask;
+ else
+ mask = sbi->options.fs_dmask;
+
+ perm = *mode_ptr & ~(S_IFMT | mask);
+
+ /* Of the r and x bits, all (subject to umask) must be present.*/
+ if ((perm & 0555) != (i_mode & 0555))
+ return -EPERM;
+
+ if (exfat_mode_can_hold_ro(inode)) {
+ /*
+ * Of the w bits, either all (subject to umask) or none must be
+ * present.
+ */
+ if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask)))
+ return -EPERM;
+ } else {
+ /*
+ * If exfat_mode_can_hold_ro(inode) is false, can't change w
+ * bits.
+ */
+ if ((perm & 0222) != (0222 & ~mask))
+ return -EPERM;
+ }
+
+ *mode_ptr &= S_IFMT | perm;
+
+ return 0;
+}
+
+static void exfat_truncate(struct inode *inode, loff_t old_size)
+{
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct fs_info_t *p_fs = &(sbi->fs_info);
+ int err;
+
+ __lock_super(sb);
+
+ /*
+ * This protects against truncating a file bigger than it was then
+ * trying to write into the hole.
+ */
+ if (EXFAT_I(inode)->mmu_private > i_size_read(inode))
+ EXFAT_I(inode)->mmu_private = i_size_read(inode);
+
+ if (EXFAT_I(inode)->fid.start_clu == 0)
+ goto out;
+
+ err = ffsTruncateFile(inode, old_size, i_size_read(inode));
+ if (err)
+ goto out;
+
+ inode->i_ctime = inode->i_mtime = current_time(inode);
+ if (IS_DIRSYNC(inode))
+ (void)exfat_sync_inode(inode);
+ else
+ mark_inode_dirty(inode);
+
+ inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) &
+ ~((loff_t)p_fs->cluster_size - 1)) >> 9;
+out:
+ __unlock_super(sb);
+}
+
+static int exfat_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb);
+ struct inode *inode = dentry->d_inode;
+ unsigned int ia_valid;
+ int error;
+ loff_t old_size;
+
+ pr_debug("%s entered\n", __func__);
+
+ if ((attr->ia_valid & ATTR_SIZE)
+ && (attr->ia_size > i_size_read(inode))) {
+ error = exfat_cont_expand(inode, attr->ia_size);
+ if (error || attr->ia_valid == ATTR_SIZE)
+ return error;
+ attr->ia_valid &= ~ATTR_SIZE;
+ }
+
+ ia_valid = attr->ia_valid;
+
+ if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET))
+ && exfat_allow_set_time(sbi, inode)) {
+ attr->ia_valid &= ~(ATTR_MTIME_SET |
+ ATTR_ATIME_SET |
+ ATTR_TIMES_SET);
+ }
+
+ error = setattr_prepare(dentry, attr);
+ attr->ia_valid = ia_valid;
+ if (error)
+ return error;
+
+ if (((attr->ia_valid & ATTR_UID) &&
+ (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
+ ((attr->ia_valid & ATTR_GID) &&
+ (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) ||
+ ((attr->ia_valid & ATTR_MODE) &&
+ (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) {
+ return -EPERM;
+ }
+
+ /*
+ * We don't return -EPERM here. Yes, strange, but this is too
+ * old behavior.
+ */
+ if (attr->ia_valid & ATTR_MODE) {
+ if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0)
+ attr->ia_valid &= ~ATTR_MODE;
+ }
+
+ EXFAT_I(inode)->fid.size = i_size_read(inode);
+
+ if (attr->ia_valid & ATTR_SIZE) {
+ old_size = i_size_read(inode);
+ down_write(&EXFAT_I(inode)->truncate_lock);
+ truncate_setsize(inode, attr->ia_size);
+ exfat_truncate(inode, old_size);
+ up_write(&EXFAT_I(inode)->truncate_lock);
+ }
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+
+ pr_debug("%s exited\n", __func__);
+ return error;
+}
+
+static int exfat_getattr(const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int flags)
+{
+ struct inode *inode = path->dentry->d_inode;
+
+ pr_debug("%s entered\n", __func__);
+
+ generic_fillattr(inode, stat);
+ stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size;
+
+ pr_debug("%s exited\n", __func__);
+ return 0;
+}
+
+static const struct inode_operations exfat_dir_inode_operations = {
+ .create = exfat_create,
+ .lookup = exfat_lookup,
+ .unlink = exfat_unlink,
+ .symlink = exfat_symlink,
+ .mkdir = exfat_mkdir,
+ .rmdir = exfat_rmdir,
+ .rename = exfat_rename,
+ .setattr = exfat_setattr,
+ .getattr = exfat_getattr,
+};
+
+/*======================================================================*/
+/* File Operations */
+/*======================================================================*/
+static const char *exfat_get_link(struct dentry *dentry, struct inode *inode,
+ struct delayed_call *done)
+{
+ struct exfat_inode_info *ei = EXFAT_I(inode);
+
+ if (ei->target) {
+ char *cookie = ei->target;
+
+ if (cookie)
+ return (char *)(ei->target);
+ }
+ return NULL;
+}
+
+static const struct inode_operations exfat_symlink_inode_operations = {
+ .get_link = exfat_get_link,
+};
+
+static int exfat_file_release(struct inode *inode, struct file *filp)
+{
+ struct super_block *sb = inode->i_sb;
+
+ EXFAT_I(inode)->fid.size = i_size_read(inode);
+ ffsSyncVol(sb, false);
+ return 0;
+}
+
+static const struct file_operations exfat_file_operations = {
+ .llseek = generic_file_llseek,
+ .read_iter = generic_file_read_iter,
+ .write_iter = generic_file_write_iter,
+ .mmap = generic_file_mmap,
+ .release = exfat_file_release,
+ .unlocked_ioctl = exfat_generic_ioctl,
+ .fsync = generic_file_fsync,
+ .splice_read = generic_file_splice_read,
+};
+
+static const struct inode_operations exfat_file_inode_operations = {
+ .setattr = exfat_setattr,
+ .getattr = exfat_getattr,
+};
+
+/*======================================================================*/
+/* Address Space Operations */
+/*======================================================================*/
+
+static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
+ unsigned long *mapped_blocks, int *create)
+{
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct fs_info_t *p_fs = &(sbi->fs_info);
+ struct bd_info_t *p_bd = &(sbi->bd_info);
+ const unsigned long blocksize = sb->s_blocksize;
+ const unsigned char blocksize_bits = sb->s_blocksize_bits;
+ sector_t last_block;
+ int err, clu_offset, sec_offset;
+ unsigned int cluster;
+
+ *phys = 0;
+ *mapped_blocks = 0;
+
+ if ((p_fs->vol_type == FAT12) || (p_fs->vol_type == FAT16)) {
+ if (inode->i_ino == EXFAT_ROOT_INO) {
+ if (sector <
+ (p_fs->dentries_in_root >>
+ (p_bd->sector_size_bits - DENTRY_SIZE_BITS))) {
+ *phys = sector + p_fs->root_start_sector;
+ *mapped_blocks = 1;
+ }
+ return 0;
+ }
+ }
+
+ last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
+ if (sector >= last_block) {
+ if (*create == 0)
+ return 0;
+ } else {
+ *create = 0;
+ }
+
+ /* cluster offset */
+ clu_offset = sector >> p_fs->sectors_per_clu_bits;
+
+ /* sector offset in cluster */
+ sec_offset = sector & (p_fs->sectors_per_clu - 1);
+
+ EXFAT_I(inode)->fid.size = i_size_read(inode);
+
+ err = ffsMapCluster(inode, clu_offset, &cluster);
+
+ if (err) {
+ if (err == FFS_FULL)
+ return -ENOSPC;
+ else
+ return -EIO;
+ } else if (cluster != CLUSTER_32(~0)) {
+ *phys = START_SECTOR(cluster) + sec_offset;
+ *mapped_blocks = p_fs->sectors_per_clu - sec_offset;
+ }
+
+ return 0;
+}
+
+static int exfat_get_block(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create)
+{
+ struct super_block *sb = inode->i_sb;
+ unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
+ int err;
+ unsigned long mapped_blocks;
+ sector_t phys;
+
+ __lock_super(sb);
+
+ err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create);
+ if (err) {
+ __unlock_super(sb);
+ return err;
+ }
+
+ if (phys) {
+ max_blocks = min(mapped_blocks, max_blocks);
+ if (create) {
+ EXFAT_I(inode)->mmu_private += max_blocks <<
+ sb->s_blocksize_bits;
+ set_buffer_new(bh_result);
+ }
+ map_bh(bh_result, sb, phys);
+ }
+
+ bh_result->b_size = max_blocks << sb->s_blocksize_bits;
+ __unlock_super(sb);
+
+ return 0;
+}
+
+static int exfat_readpage(struct file *file, struct page *page)
+{
+ return mpage_readpage(page, exfat_get_block);
+}
+
+static int exfat_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *pages, unsigned int nr_pages)
+{
+ return mpage_readpages(mapping, pages, nr_pages, exfat_get_block);
+}
+
+static int exfat_writepage(struct page *page, struct writeback_control *wbc)
+{
+ return block_write_full_page(page, exfat_get_block, wbc);
+}
+
+static int exfat_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ return mpage_writepages(mapping, wbc, exfat_get_block);
+}
+
+static void exfat_write_failed(struct address_space *mapping, loff_t to)
+{
+ struct inode *inode = mapping->host;
+
+ if (to > i_size_read(inode)) {
+ truncate_pagecache(inode, i_size_read(inode));
+ EXFAT_I(inode)->fid.size = i_size_read(inode);
+ exfat_truncate(inode, i_size_read(inode));
+ }
+}
+
+static int exfat_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned int len, unsigned int flags,
+ struct page **pagep, void **fsdata)
+{
+ int ret;
+
+ *pagep = NULL;
+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ exfat_get_block,
+ &EXFAT_I(mapping->host)->mmu_private);
+
+ if (ret < 0)
+ exfat_write_failed(mapping, pos + len);
+ return ret;
+}
+
+static int exfat_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned int len, unsigned int copied,
+ struct page *pagep, void *fsdata)
+{
+ struct inode *inode = mapping->host;
+ struct file_id_t *fid = &(EXFAT_I(inode)->fid);
+ int err;
+
+ err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
+
+ if (err < len)
+ exfat_write_failed(mapping, pos + len);
+
+ if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) {
+ inode->i_mtime = inode->i_ctime = current_time(inode);
+ fid->attr |= ATTR_ARCHIVE;
+ mark_inode_dirty(inode);
+ }
+ return err;
+}
+
+static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
+{
+ struct inode *inode = iocb->ki_filp->f_mapping->host;
+ struct address_space *mapping = iocb->ki_filp->f_mapping;
+ ssize_t ret;
+ int rw;
+
+ rw = iov_iter_rw(iter);
+
+ if (rw == WRITE) {
+ if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter))
+ return 0;
+ }
+ ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block);
+
+ if ((ret < 0) && (rw & WRITE))
+ exfat_write_failed(mapping, iov_iter_count(iter));
+ return ret;
+}
+
+static sector_t _exfat_bmap(struct address_space *mapping, sector_t block)
+{
+ sector_t blocknr;
+
+ /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */
+ down_read(&EXFAT_I(mapping->host)->truncate_lock);
+ blocknr = generic_block_bmap(mapping, block, exfat_get_block);
+ up_read(&EXFAT_I(mapping->host)->truncate_lock);
+
+ return blocknr;
+}
+
+static const struct address_space_operations exfat_aops = {
+ .readpage = exfat_readpage,
+ .readpages = exfat_readpages,
+ .writepage = exfat_writepage,
+ .writepages = exfat_writepages,
+ .write_begin = exfat_write_begin,
+ .write_end = exfat_write_end,
+ .direct_IO = exfat_direct_IO,
+ .bmap = _exfat_bmap
+};
+
+/*======================================================================*/
+/* Super Operations */
+/*======================================================================*/
+
+static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct exfat_inode_info *info;
+ struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos);
+ struct inode *inode = NULL;
+
+ spin_lock(&sbi->inode_hash_lock);
+ hlist_for_each_entry(info, head, i_hash_fat) {
+ BUG_ON(info->vfs_inode.i_sb != sb);
+
+ if (i_pos != info->i_pos)
+ continue;
+ inode = igrab(&info->vfs_inode);
+ if (inode)
+ break;
+ }
+ spin_unlock(&sbi->inode_hash_lock);
+ return inode;
+}
+
+/* doesn't deal with root inode */
+static int exfat_fill_inode(struct inode *inode, struct file_id_t *fid)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
+ struct fs_info_t *p_fs = &(sbi->fs_info);
+ struct dir_entry_t info;
+
+ memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(struct file_id_t));
+
+ ffsReadStat(inode, &info);
+
+ EXFAT_I(inode)->i_pos = 0;
+ EXFAT_I(inode)->target = NULL;
+ inode->i_uid = sbi->options.fs_uid;
+ inode->i_gid = sbi->options.fs_gid;
+ INC_IVERSION(inode);
+ inode->i_generation = get_seconds();
+
+ if (info.Attr & ATTR_SUBDIR) { /* directory */
+ inode->i_generation &= ~1;
+ inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777);
+ inode->i_op = &exfat_dir_inode_operations;
+ inode->i_fop = &exfat_dir_operations;
+
+ i_size_write(inode, info.Size);
+ EXFAT_I(inode)->mmu_private = i_size_read(inode);
+ set_nlink(inode, info.NumSubdirs);
+ } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */
+ inode->i_generation |= 1;
+ inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777);
+ inode->i_op = &exfat_symlink_inode_operations;
+
+ i_size_write(inode, info.Size);
+ EXFAT_I(inode)->mmu_private = i_size_read(inode);
+ } else { /* regular file */
+ inode->i_generation |= 1;
+ inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777);
+ inode->i_op = &exfat_file_inode_operations;
+ inode->i_fop = &exfat_file_operations;
+ inode->i_mapping->a_ops = &exfat_aops;
+ inode->i_mapping->nrpages = 0;
+
+ i_size_write(inode, info.Size);
+ EXFAT_I(inode)->mmu_private = i_size_read(inode);
+ }
+ exfat_save_attr(inode, info.Attr);
+
+ inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1))
+ & ~((loff_t)p_fs->cluster_size - 1)) >> 9;
+
+ exfat_time_fat2unix(&inode->i_mtime, &info.ModifyTimestamp);
+ exfat_time_fat2unix(&inode->i_ctime, &info.CreateTimestamp);
+ exfat_time_fat2unix(&inode->i_atime, &info.AccessTimestamp);
+
+ return 0;
+}
+
+static struct inode *exfat_build_inode(struct super_block *sb,
+ struct file_id_t *fid, loff_t i_pos)
+{
+ struct inode *inode;
+ int err;
+
+ inode = exfat_iget(sb, i_pos);
+ if (inode)
+ goto out;
+ inode = new_inode(sb);
+ if (!inode) {
+ inode = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+ inode->i_ino = iunique(sb, EXFAT_ROOT_INO);
+ SET_IVERSION(inode, 1);
+ err = exfat_fill_inode(inode, fid);
+ if (err) {
+ iput(inode);
+ inode = ERR_PTR(err);
+ goto out;
+ }
+ exfat_attach(inode, i_pos);
+ insert_inode_hash(inode);
+out:
+ return inode;
+}
+
+static int exfat_sync_inode(struct inode *inode)
+{
+ return exfat_write_inode(inode, NULL);
+}
+
+static struct inode *exfat_alloc_inode(struct super_block *sb)
+{
+ struct exfat_inode_info *ei;
+
+ ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS);
+ if (!ei)
+ return NULL;
+
+ init_rwsem(&ei->truncate_lock);
+
+ return &ei->vfs_inode;
+}
+
+static void exfat_destroy_inode(struct inode *inode)
+{
+ kfree(EXFAT_I(inode)->target);
+ EXFAT_I(inode)->target = NULL;
+
+ kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode));
+}
+
+static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
+{
+ struct dir_entry_t info;
+
+ if (inode->i_ino == EXFAT_ROOT_INO)
+ return 0;
+
+ info.Attr = exfat_make_attr(inode);
+ info.Size = i_size_read(inode);
+
+ exfat_time_unix2fat(&inode->i_mtime, &info.ModifyTimestamp);
+ exfat_time_unix2fat(&inode->i_ctime, &info.CreateTimestamp);
+ exfat_time_unix2fat(&inode->i_atime, &info.AccessTimestamp);
+
+ ffsWriteStat(inode, &info);
+
+ return 0;
+}
+
+static void exfat_evict_inode(struct inode *inode)
+{
+ truncate_inode_pages(&inode->i_data, 0);
+
+ if (!inode->i_nlink)
+ i_size_write(inode, 0);
+ invalidate_inode_buffers(inode);
+ clear_inode(inode);
+ exfat_detach(inode);
+
+ remove_inode_hash(inode);
+}
+
+static void exfat_free_super(struct exfat_sb_info *sbi)
+{
+ if (sbi->nls_disk)
+ unload_nls(sbi->nls_disk);
+ if (sbi->nls_io)
+ unload_nls(sbi->nls_io);
+ if (sbi->options.iocharset != exfat_default_iocharset)
+ kfree(sbi->options.iocharset);
+ /* mutex_init is in exfat_fill_super function. only for 3.7+ */
+ mutex_destroy(&sbi->s_lock);
+ kfree(sbi);
+}
+
+static void exfat_put_super(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ if (__is_sb_dirty(sb))
+ exfat_write_super(sb);
+
+ ffsUmountVol(sb);
+
+ sb->s_fs_info = NULL;
+ exfat_free_super(sbi);
+}
+
+static void exfat_write_super(struct super_block *sb)
+{
+ __lock_super(sb);
+
+ __set_sb_clean(sb);
+
+ if (!sb_rdonly(sb))
+ ffsSyncVol(sb, true);
+
+ __unlock_super(sb);
+}
+
+static int exfat_sync_fs(struct super_block *sb, int wait)
+{
+ int err = 0;
+
+ if (__is_sb_dirty(sb)) {
+ __lock_super(sb);
+ __set_sb_clean(sb);
+ err = ffsSyncVol(sb, true);
+ __unlock_super(sb);
+ }
+
+ return err;
+}
+
+static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ struct super_block *sb = dentry->d_sb;
+ u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ struct vol_info_t info;
+
+ if (p_fs->used_clusters == UINT_MAX) {
+ if (ffsGetVolInfo(sb, &info) == FFS_MEDIAERR)
+ return -EIO;
+
+ } else {
+ info.FatType = p_fs->vol_type;
+ info.ClusterSize = p_fs->cluster_size;
+ info.NumClusters = p_fs->num_clusters - 2;
+ info.UsedClusters = p_fs->used_clusters;
+ info.FreeClusters = info.NumClusters - info.UsedClusters;
+
+ if (p_fs->dev_ejected)
+ pr_info("[EXFAT] statfs on device that is ejected\n");
+ }
+
+ buf->f_type = sb->s_magic;
+ buf->f_bsize = info.ClusterSize;
+ buf->f_blocks = info.NumClusters;
+ buf->f_bfree = info.FreeClusters;
+ buf->f_bavail = info.FreeClusters;
+ buf->f_fsid.val[0] = (u32)id;
+ buf->f_fsid.val[1] = (u32)(id >> 32);
+ buf->f_namelen = 260;
+
+ return 0;
+}
+
+static int exfat_remount(struct super_block *sb, int *flags, char *data)
+{
+ *flags |= SB_NODIRATIME;
+ return 0;
+}
+
+static int exfat_show_options(struct seq_file *m, struct dentry *root)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb);
+ struct exfat_mount_options *opts = &sbi->options;
+
+ if (__kuid_val(opts->fs_uid))
+ seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid));
+ if (__kgid_val(opts->fs_gid))
+ seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid));
+ seq_printf(m, ",fmask=%04o", opts->fs_fmask);
+ seq_printf(m, ",dmask=%04o", opts->fs_dmask);
+ if (opts->allow_utime)
+ seq_printf(m, ",allow_utime=%04o", opts->allow_utime);
+ if (sbi->nls_disk)
+ seq_printf(m, ",codepage=%s", sbi->nls_disk->charset);
+ if (sbi->nls_io)
+ seq_printf(m, ",iocharset=%s", sbi->nls_io->charset);
+ seq_printf(m, ",namecase=%u", opts->casesensitive);
+ if (opts->errors == EXFAT_ERRORS_CONT)
+ seq_puts(m, ",errors=continue");
+ else if (opts->errors == EXFAT_ERRORS_PANIC)
+ seq_puts(m, ",errors=panic");
+ else
+ seq_puts(m, ",errors=remount-ro");
+#ifdef CONFIG_EXFAT_DISCARD
+ if (opts->discard)
+ seq_puts(m, ",discard");
+#endif
+ return 0;
+}
+
+static const struct super_operations exfat_sops = {
+ .alloc_inode = exfat_alloc_inode,
+ .destroy_inode = exfat_destroy_inode,
+ .write_inode = exfat_write_inode,
+ .evict_inode = exfat_evict_inode,
+ .put_super = exfat_put_super,
+ .sync_fs = exfat_sync_fs,
+ .statfs = exfat_statfs,
+ .remount_fs = exfat_remount,
+ .show_options = exfat_show_options,
+};
+
+/*======================================================================*/
+/* Export Operations */
+/*======================================================================*/
+
+static struct inode *exfat_nfs_get_inode(struct super_block *sb, u64 ino,
+ u32 generation)
+{
+ struct inode *inode = NULL;
+
+ if (ino < EXFAT_ROOT_INO)
+ return inode;
+ inode = ilookup(sb, ino);
+
+ if (inode && generation && (inode->i_generation != generation)) {
+ iput(inode);
+ inode = NULL;
+ }
+
+ return inode;
+}
+
+static struct dentry *exfat_fh_to_dentry(struct super_block *sb,
+ struct fid *fid, int fh_len,
+ int fh_type)
+{
+ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+ exfat_nfs_get_inode);
+}
+
+static struct dentry *exfat_fh_to_parent(struct super_block *sb,
+ struct fid *fid, int fh_len,
+ int fh_type)
+{
+ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+ exfat_nfs_get_inode);
+}
+
+static const struct export_operations exfat_export_ops = {
+ .fh_to_dentry = exfat_fh_to_dentry,
+ .fh_to_parent = exfat_fh_to_parent,
+};
+
+/*======================================================================*/
+/* Super Block Read Operations */
+/*======================================================================*/
+
+enum {
+ Opt_uid,
+ Opt_gid,
+ Opt_umask,
+ Opt_dmask,
+ Opt_fmask,
+ Opt_allow_utime,
+ Opt_codepage,
+ Opt_charset,
+ Opt_namecase,
+ Opt_debug,
+ Opt_err_cont,
+ Opt_err_panic,
+ Opt_err_ro,
+ Opt_utf8_hack,
+ Opt_err,
+#ifdef CONFIG_EXFAT_DISCARD
+ Opt_discard,
+#endif /* EXFAT_CONFIG_DISCARD */
+};
+
+static const match_table_t exfat_tokens = {
+ {Opt_uid, "uid=%u"},
+ {Opt_gid, "gid=%u"},
+ {Opt_umask, "umask=%o"},
+ {Opt_dmask, "dmask=%o"},
+ {Opt_fmask, "fmask=%o"},
+ {Opt_allow_utime, "allow_utime=%o"},
+ {Opt_codepage, "codepage=%u"},
+ {Opt_charset, "iocharset=%s"},
+ {Opt_namecase, "namecase=%u"},
+ {Opt_debug, "debug"},
+ {Opt_err_cont, "errors=continue"},
+ {Opt_err_panic, "errors=panic"},
+ {Opt_err_ro, "errors=remount-ro"},
+ {Opt_utf8_hack, "utf8"},
+#ifdef CONFIG_EXFAT_DISCARD
+ {Opt_discard, "discard"},
+#endif /* CONFIG_EXFAT_DISCARD */
+ {Opt_err, NULL}
+};
+
+static int parse_options(char *options, int silent, int *debug,
+ struct exfat_mount_options *opts)
+{
+ char *p;
+ substring_t args[MAX_OPT_ARGS];
+ int option;
+ char *iocharset;
+
+ opts->fs_uid = current_uid();
+ opts->fs_gid = current_gid();
+ opts->fs_fmask = opts->fs_dmask = current->fs->umask;
+ opts->allow_utime = U16_MAX;
+ opts->codepage = exfat_default_codepage;
+ opts->iocharset = exfat_default_iocharset;
+ opts->casesensitive = 0;
+ opts->errors = EXFAT_ERRORS_RO;
+#ifdef CONFIG_EXFAT_DISCARD
+ opts->discard = 0;
+#endif
+ *debug = 0;
+
+ if (!options)
+ goto out;
+
+ while ((p = strsep(&options, ","))) {
+ int token;
+
+ if (!*p)
+ continue;
+
+ token = match_token(p, exfat_tokens, args);
+ switch (token) {
+ case Opt_uid:
+ if (match_int(&args[0], &option))
+ return 0;
+ opts->fs_uid = KUIDT_INIT(option);
+ break;
+ case Opt_gid:
+ if (match_int(&args[0], &option))
+ return 0;
+ opts->fs_gid = KGIDT_INIT(option);
+ break;
+ case Opt_umask:
+ case Opt_dmask:
+ case Opt_fmask:
+ if (match_octal(&args[0], &option))
+ return 0;
+ if (token != Opt_dmask)
+ opts->fs_fmask = option;
+ if (token != Opt_fmask)
+ opts->fs_dmask = option;
+ break;
+ case Opt_allow_utime:
+ if (match_octal(&args[0], &option))
+ return 0;
+ opts->allow_utime = option & 0022;
+ break;
+ case Opt_codepage:
+ if (match_int(&args[0], &option))
+ return 0;
+ opts->codepage = option;
+ break;
+ case Opt_charset:
+ if (opts->iocharset != exfat_default_iocharset)
+ kfree(opts->iocharset);
+ iocharset = match_strdup(&args[0]);
+ if (!iocharset)
+ return -ENOMEM;
+ opts->iocharset = iocharset;
+ break;
+ case Opt_namecase:
+ if (match_int(&args[0], &option))
+ return 0;
+ opts->casesensitive = option;
+ break;
+ case Opt_err_cont:
+ opts->errors = EXFAT_ERRORS_CONT;
+ break;
+ case Opt_err_panic:
+ opts->errors = EXFAT_ERRORS_PANIC;
+ break;
+ case Opt_err_ro:
+ opts->errors = EXFAT_ERRORS_RO;
+ break;
+ case Opt_debug:
+ *debug = 1;
+ break;
+#ifdef CONFIG_EXFAT_DISCARD
+ case Opt_discard:
+ opts->discard = 1;
+ break;
+#endif /* CONFIG_EXFAT_DISCARD */
+ case Opt_utf8_hack:
+ break;
+ default:
+ if (!silent)
+ pr_err("[EXFAT] Unrecognized mount option %s or missing value\n",
+ p);
+ return -EINVAL;
+ }
+ }
+
+out:
+ if (opts->allow_utime == U16_MAX)
+ opts->allow_utime = ~opts->fs_dmask & 0022;
+
+ return 0;
+}
+
+static void exfat_hash_init(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ int i;
+
+ spin_lock_init(&sbi->inode_hash_lock);
+ for (i = 0; i < EXFAT_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&sbi->inode_hashtable[i]);
+}
+
+static int exfat_read_root(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct fs_info_t *p_fs = &(sbi->fs_info);
+ struct dir_entry_t info;
+
+ EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir;
+ EXFAT_I(inode)->fid.dir.flags = 0x01;
+ EXFAT_I(inode)->fid.entry = -1;
+ EXFAT_I(inode)->fid.start_clu = p_fs->root_dir;
+ EXFAT_I(inode)->fid.flags = 0x01;
+ EXFAT_I(inode)->fid.type = TYPE_DIR;
+ EXFAT_I(inode)->fid.rwoffset = 0;
+ EXFAT_I(inode)->fid.hint_last_off = -1;
+
+ EXFAT_I(inode)->target = NULL;
+
+ ffsReadStat(inode, &info);
+
+ inode->i_uid = sbi->options.fs_uid;
+ inode->i_gid = sbi->options.fs_gid;
+ INC_IVERSION(inode);
+ inode->i_generation = 0;
+ inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777);
+ inode->i_op = &exfat_dir_inode_operations;
+ inode->i_fop = &exfat_dir_operations;
+
+ i_size_write(inode, info.Size);
+ inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1))
+ & ~((loff_t)p_fs->cluster_size - 1)) >> 9;
+ EXFAT_I(inode)->i_pos = ((loff_t)p_fs->root_dir << 32) | 0xffffffff;
+ EXFAT_I(inode)->mmu_private = i_size_read(inode);
+
+ exfat_save_attr(inode, ATTR_SUBDIR);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+ set_nlink(inode, info.NumSubdirs + 2);
+
+ return 0;
+}
+
+static void setup_dops(struct super_block *sb)
+{
+ if (EXFAT_SB(sb)->options.casesensitive == 0)
+ sb->s_d_op = &exfat_ci_dentry_ops;
+ else
+ sb->s_d_op = &exfat_dentry_ops;
+}
+
+static int exfat_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct inode *root_inode = NULL;
+ struct exfat_sb_info *sbi;
+ int debug, ret;
+ long error;
+ char buf[50];
+
+ /*
+ * GFP_KERNEL is ok here, because while we do hold the
+ * supeblock lock, memory pressure can't call back into
+ * the filesystem, since we're only just about to mount
+ * it and have no inodes etc active!
+ */
+ sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ mutex_init(&sbi->s_lock);
+ sb->s_fs_info = sbi;
+ sb->s_flags |= SB_NODIRATIME;
+ sb->s_magic = EXFAT_SUPER_MAGIC;
+ sb->s_op = &exfat_sops;
+ sb->s_export_op = &exfat_export_ops;
+
+ error = parse_options(data, silent, &debug, &sbi->options);
+ if (error)
+ goto out_fail;
+
+ setup_dops(sb);
+
+ error = -EIO;
+ sb_min_blocksize(sb, 512);
+ sb->s_maxbytes = 0x7fffffffffffffffLL; /* maximum file size */
+
+ ret = ffsMountVol(sb);
+ if (ret) {
+ if (!silent)
+ pr_err("[EXFAT] ffsMountVol failed\n");
+
+ goto out_fail;
+ }
+
+ /* set up enough so that it can read an inode */
+ exfat_hash_init(sb);
+
+ /*
+ * The low byte of FAT's first entry must have same value with
+ * media-field. But in real world, too many devices is
+ * writing wrong value. So, removed that validity check.
+ *
+ * if (FAT_FIRST_ENT(sb, media) != first)
+ */
+
+ /* codepage is not meaningful in exfat */
+ if (sbi->fs_info.vol_type != EXFAT) {
+ error = -EINVAL;
+ sprintf(buf, "cp%d", sbi->options.codepage);
+ sbi->nls_disk = load_nls(buf);
+ if (!sbi->nls_disk) {
+ pr_err("[EXFAT] Codepage %s not found\n", buf);
+ goto out_fail2;
+ }
+ }
+
+ sbi->nls_io = load_nls(sbi->options.iocharset);
+
+ error = -ENOMEM;
+ root_inode = new_inode(sb);
+ if (!root_inode)
+ goto out_fail2;
+ root_inode->i_ino = EXFAT_ROOT_INO;
+ SET_IVERSION(root_inode, 1);
+
+ error = exfat_read_root(root_inode);
+ if (error < 0)
+ goto out_fail2;
+ error = -ENOMEM;
+ exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos);
+ insert_inode_hash(root_inode);
+ sb->s_root = d_make_root(root_inode);
+ if (!sb->s_root) {
+ pr_err("[EXFAT] Getting the root inode failed\n");
+ goto out_fail2;
+ }
+
+ return 0;
+
+out_fail2:
+ ffsUmountVol(sb);
+out_fail:
+ if (root_inode)
+ iput(root_inode);
+ sb->s_fs_info = NULL;
+ exfat_free_super(sbi);
+ return error;
+}
+
+static struct dentry *exfat_fs_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data)
+{
+ return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super);
+}
+
+static void init_once(void *foo)
+{
+ struct exfat_inode_info *ei = (struct exfat_inode_info *)foo;
+
+ INIT_HLIST_NODE(&ei->i_hash_fat);
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int __init exfat_init_inodecache(void)
+{
+ exfat_inode_cachep = kmem_cache_create("exfat_inode_cache",
+ sizeof(struct exfat_inode_info),
+ 0,
+ (SLAB_RECLAIM_ACCOUNT |
+ SLAB_MEM_SPREAD),
+ init_once);
+ if (!exfat_inode_cachep)
+ return -ENOMEM;
+ return 0;
+}
+
+static void __exit exfat_destroy_inodecache(void)
+{
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
+ * destroy cache.
+ */
+ rcu_barrier();
+ kmem_cache_destroy(exfat_inode_cachep);
+}
+
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+static void exfat_debug_kill_sb(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct block_device *bdev = sb->s_bdev;
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
+ long flags;
+
+ if (sbi) {
+ flags = sbi->debug_flags;
+
+ if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) {
+ /*
+ * invalidate_bdev drops all device cache include
+ * dirty. We use this to simulate device removal.
+ */
+ down(&p_fs->v_sem);
+ FAT_release_all(sb);
+ buf_release_all(sb);
+ up(&p_fs->v_sem);
+
+ invalidate_bdev(bdev);
+ }
+ }
+
+ kill_block_super(sb);
+}
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+static struct file_system_type exfat_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "exfat",
+ .mount = exfat_fs_mount,
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ .kill_sb = exfat_debug_kill_sb,
+#else
+ .kill_sb = kill_block_super,
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+ .fs_flags = FS_REQUIRES_DEV,
+};
+
+static int __init init_exfat(void)
+{
+ int err;
+
+ BUILD_BUG_ON(sizeof(struct dentry_t) != DENTRY_SIZE);
+ BUILD_BUG_ON(sizeof(struct dos_dentry_t) != DENTRY_SIZE);
+ BUILD_BUG_ON(sizeof(struct ext_dentry_t) != DENTRY_SIZE);
+ BUILD_BUG_ON(sizeof(struct file_dentry_t) != DENTRY_SIZE);
+ BUILD_BUG_ON(sizeof(struct strm_dentry_t) != DENTRY_SIZE);
+ BUILD_BUG_ON(sizeof(struct name_dentry_t) != DENTRY_SIZE);
+ BUILD_BUG_ON(sizeof(struct bmap_dentry_t) != DENTRY_SIZE);
+ BUILD_BUG_ON(sizeof(struct case_dentry_t) != DENTRY_SIZE);
+ BUILD_BUG_ON(sizeof(struct volm_dentry_t) != DENTRY_SIZE);
+
+ pr_info("exFAT: Version %s\n", EXFAT_VERSION);
+
+ err = exfat_init_inodecache();
+ if (err)
+ return err;
+
+ err = register_filesystem(&exfat_fs_type);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void __exit exit_exfat(void)
+{
+ exfat_destroy_inodecache();
+ unregister_filesystem(&exfat_fs_type);
+}
+
+module_init(init_exfat);
+module_exit(exit_exfat);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("exFAT Filesystem Driver");
+MODULE_ALIAS_FS("exfat");
diff --git a/drivers/staging/exfat/exfat_upcase.c b/drivers/staging/exfat/exfat_upcase.c
new file mode 100644
index 000000000000..366082fb3dab
--- /dev/null
+++ b/drivers/staging/exfat/exfat_upcase.c
@@ -0,0 +1,740 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/types.h>
+#include "exfat.h"
+
+const u8 uni_upcase[NUM_UPCASE << 1] = {
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00,
+ 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00,
+ 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00,
+ 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00,
+ 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
+ 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00,
+ 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00,
+ 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00,
+ 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00,
+ 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00,
+ 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00,
+ 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00,
+ 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00,
+ 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00,
+ 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00,
+ 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00,
+ 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
+ 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00,
+ 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00,
+ 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
+ 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
+ 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00,
+ 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00,
+ 0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00,
+ 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
+ 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00,
+ 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00,
+ 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
+ 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
+ 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00,
+ 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00,
+ 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00,
+ 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00,
+ 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00,
+ 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00,
+ 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00,
+ 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00,
+ 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00,
+ 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00,
+ 0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00,
+ 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00,
+ 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00,
+ 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00,
+ 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00,
+ 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00,
+ 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00,
+ 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00,
+ 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00,
+ 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00,
+ 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00,
+ 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00,
+ 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00,
+ 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00,
+ 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00,
+ 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00,
+ 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00,
+ 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00,
+ 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00,
+ 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00,
+ 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00,
+ 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00,
+ 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00,
+ 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01,
+ 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01,
+ 0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01,
+ 0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01,
+ 0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01,
+ 0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01,
+ 0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01,
+ 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01,
+ 0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01,
+ 0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01,
+ 0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01,
+ 0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01,
+ 0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01,
+ 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01,
+ 0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01,
+ 0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01,
+ 0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01,
+ 0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01,
+ 0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01,
+ 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01,
+ 0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01,
+ 0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01,
+ 0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01,
+ 0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01,
+ 0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01,
+ 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01,
+ 0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01,
+ 0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01,
+ 0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01,
+ 0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01,
+ 0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01,
+ 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01,
+ 0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01,
+ 0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01,
+ 0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01,
+ 0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01,
+ 0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01,
+ 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01,
+ 0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01,
+ 0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01,
+ 0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01,
+ 0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01,
+ 0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01,
+ 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01,
+ 0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01,
+ 0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01,
+ 0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01,
+ 0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01,
+ 0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01,
+ 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01,
+ 0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01,
+ 0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01,
+ 0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01,
+ 0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01,
+ 0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01,
+ 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01,
+ 0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01,
+ 0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01,
+ 0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01,
+ 0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01,
+ 0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01,
+ 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01,
+ 0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01,
+ 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01,
+ 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02,
+ 0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02,
+ 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02,
+ 0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02,
+ 0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02,
+ 0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02,
+ 0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02,
+ 0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02,
+ 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02,
+ 0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02,
+ 0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02,
+ 0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02,
+ 0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02,
+ 0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02,
+ 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02,
+ 0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02,
+ 0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02,
+ 0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02,
+ 0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02,
+ 0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01,
+ 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01,
+ 0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01,
+ 0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02,
+ 0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01,
+ 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02,
+ 0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C,
+ 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01,
+ 0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02,
+ 0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02,
+ 0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02,
+ 0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02,
+ 0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01,
+ 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02,
+ 0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01,
+ 0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02,
+ 0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02,
+ 0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02,
+ 0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02,
+ 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02,
+ 0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02,
+ 0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02,
+ 0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02,
+ 0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02,
+ 0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02,
+ 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02,
+ 0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02,
+ 0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02,
+ 0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02,
+ 0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02,
+ 0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02,
+ 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02,
+ 0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02,
+ 0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02,
+ 0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02,
+ 0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02,
+ 0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02,
+ 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02,
+ 0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02,
+ 0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02,
+ 0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02,
+ 0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02,
+ 0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02,
+ 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02,
+ 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03,
+ 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03,
+ 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03,
+ 0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03,
+ 0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03,
+ 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03,
+ 0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03,
+ 0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03,
+ 0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03,
+ 0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03,
+ 0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03,
+ 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03,
+ 0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03,
+ 0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03,
+ 0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03,
+ 0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03,
+ 0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03,
+ 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03,
+ 0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03,
+ 0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03,
+ 0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03,
+ 0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03,
+ 0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03,
+ 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03,
+ 0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03,
+ 0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03,
+ 0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03,
+ 0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03,
+ 0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03,
+ 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03,
+ 0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03,
+ 0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03,
+ 0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03,
+ 0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03,
+ 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03,
+ 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03,
+ 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
+ 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
+ 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03,
+ 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03,
+ 0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03,
+ 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03,
+ 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03,
+ 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03,
+ 0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
+ 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
+ 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03,
+ 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03,
+ 0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03,
+ 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03,
+ 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03,
+ 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03,
+ 0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03,
+ 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03,
+ 0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03,
+ 0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03,
+ 0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03,
+ 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03,
+ 0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03,
+ 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03,
+ 0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03,
+ 0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03,
+ 0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03,
+ 0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03,
+ 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04,
+ 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
+ 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04,
+ 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04,
+ 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
+ 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
+ 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04,
+ 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04,
+ 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
+ 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
+ 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04,
+ 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04,
+ 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
+ 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
+ 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04,
+ 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04,
+ 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
+ 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
+ 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04,
+ 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04,
+ 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04,
+ 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
+ 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04,
+ 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04,
+ 0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04,
+ 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04,
+ 0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04,
+ 0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04,
+ 0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04,
+ 0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04,
+ 0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04,
+ 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04,
+ 0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04,
+ 0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04,
+ 0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04,
+ 0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04,
+ 0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04,
+ 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04,
+ 0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04,
+ 0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04,
+ 0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04,
+ 0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04,
+ 0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04,
+ 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04,
+ 0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04,
+ 0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04,
+ 0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04,
+ 0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04,
+ 0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04,
+ 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04,
+ 0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04,
+ 0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04,
+ 0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04,
+ 0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04,
+ 0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04,
+ 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04,
+ 0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04,
+ 0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04,
+ 0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04,
+ 0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04,
+ 0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04,
+ 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04,
+ 0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04,
+ 0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04,
+ 0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05,
+ 0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05,
+ 0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05,
+ 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05,
+ 0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05,
+ 0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05,
+ 0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05,
+ 0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05,
+ 0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05,
+ 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05,
+ 0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05,
+ 0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05,
+ 0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
+ 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
+ 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05,
+ 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05,
+ 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05,
+ 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
+ 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05,
+ 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05,
+ 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05,
+ 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05,
+ 0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05,
+ 0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05,
+ 0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
+ 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
+ 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05,
+ 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05,
+ 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05,
+ 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
+ 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05,
+ 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05,
+ 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05,
+ 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF,
+ 0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D,
+ 0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D,
+ 0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D,
+ 0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D,
+ 0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D,
+ 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D,
+ 0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D,
+ 0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D,
+ 0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D,
+ 0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D,
+ 0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D,
+ 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D,
+ 0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D,
+ 0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D,
+ 0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D,
+ 0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D,
+ 0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D,
+ 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D,
+ 0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D,
+ 0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D,
+ 0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D,
+ 0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D,
+ 0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D,
+ 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D,
+ 0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D,
+ 0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D,
+ 0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D,
+ 0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D,
+ 0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D,
+ 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D,
+ 0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D,
+ 0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D,
+ 0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D,
+ 0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E,
+ 0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E,
+ 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E,
+ 0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E,
+ 0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E,
+ 0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E,
+ 0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E,
+ 0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
+ 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E,
+ 0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E,
+ 0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E,
+ 0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E,
+ 0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E,
+ 0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E,
+ 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E,
+ 0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E,
+ 0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E,
+ 0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E,
+ 0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E,
+ 0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E,
+ 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E,
+ 0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E,
+ 0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E,
+ 0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E,
+ 0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E,
+ 0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E,
+ 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E,
+ 0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E,
+ 0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E,
+ 0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E,
+ 0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E,
+ 0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E,
+ 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E,
+ 0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E,
+ 0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E,
+ 0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E,
+ 0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E,
+ 0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E,
+ 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E,
+ 0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E,
+ 0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E,
+ 0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E,
+ 0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E,
+ 0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E,
+ 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E,
+ 0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E,
+ 0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E,
+ 0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E,
+ 0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E,
+ 0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E,
+ 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E,
+ 0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E,
+ 0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E,
+ 0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E,
+ 0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E,
+ 0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E,
+ 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E,
+ 0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E,
+ 0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E,
+ 0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E,
+ 0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E,
+ 0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E,
+ 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E,
+ 0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E,
+ 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F,
+ 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F,
+ 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F,
+ 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F,
+ 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F,
+ 0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F,
+ 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F,
+ 0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F,
+ 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F,
+ 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F,
+ 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F,
+ 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F,
+ 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F,
+ 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F,
+ 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F,
+ 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F,
+ 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F,
+ 0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F,
+ 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F,
+ 0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F,
+ 0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F,
+ 0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F,
+ 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F,
+ 0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F,
+ 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F,
+ 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F,
+ 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F,
+ 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F,
+ 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F,
+ 0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F,
+ 0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F,
+ 0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F,
+ 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F,
+ 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F,
+ 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F,
+ 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F,
+ 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F,
+ 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F,
+ 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F,
+ 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F,
+ 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F,
+ 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F,
+ 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F,
+ 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F,
+ 0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F,
+ 0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F,
+ 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F,
+ 0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F,
+ 0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F,
+ 0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F,
+ 0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F,
+ 0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F,
+ 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F,
+ 0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F,
+ 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F,
+ 0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F,
+ 0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F,
+ 0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F,
+ 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F,
+ 0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F,
+ 0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F,
+ 0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F,
+ 0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F,
+ 0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F,
+ 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20,
+ 0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20,
+ 0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20,
+ 0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20,
+ 0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20,
+ 0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20,
+ 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20,
+ 0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20,
+ 0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20,
+ 0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20,
+ 0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20,
+ 0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20,
+ 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20,
+ 0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20,
+ 0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20,
+ 0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20,
+ 0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20,
+ 0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20,
+ 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20,
+ 0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20,
+ 0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20,
+ 0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20,
+ 0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20,
+ 0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20,
+ 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20,
+ 0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20,
+ 0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20,
+ 0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20,
+ 0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20,
+ 0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20,
+ 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20,
+ 0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20,
+ 0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20,
+ 0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20,
+ 0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20,
+ 0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20,
+ 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20,
+ 0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20,
+ 0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20,
+ 0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20,
+ 0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20,
+ 0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20,
+ 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20,
+ 0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20,
+ 0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20,
+ 0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20,
+ 0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20,
+ 0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20,
+ 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20,
+ 0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20,
+ 0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20,
+ 0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20,
+ 0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20,
+ 0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20,
+ 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20,
+ 0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20,
+ 0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20,
+ 0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20,
+ 0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20,
+ 0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20,
+ 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20,
+ 0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20,
+ 0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20,
+ 0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20,
+ 0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21,
+ 0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21,
+ 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21,
+ 0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21,
+ 0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21,
+ 0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21,
+ 0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21,
+ 0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21,
+ 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21,
+ 0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21,
+ 0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21,
+ 0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21,
+ 0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21,
+ 0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21,
+ 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21,
+ 0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21,
+ 0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21,
+ 0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21,
+ 0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21,
+ 0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21,
+ 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21,
+ 0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21,
+ 0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21,
+ 0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21,
+ 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
+ 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
+ 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21,
+ 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21,
+ 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
+ 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
+ 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21,
+ 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21,
+ 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21,
+ 0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24,
+ 0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24,
+ 0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24,
+ 0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24,
+ 0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24,
+ 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24,
+ 0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24,
+ 0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C,
+ 0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C,
+ 0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C,
+ 0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C,
+ 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C,
+ 0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C,
+ 0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C,
+ 0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C,
+ 0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C,
+ 0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C,
+ 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C,
+ 0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C,
+ 0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C,
+ 0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C,
+ 0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C,
+ 0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C,
+ 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C,
+ 0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C,
+ 0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C,
+ 0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C,
+ 0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C,
+ 0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C,
+ 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C,
+ 0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C,
+ 0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C,
+ 0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C,
+ 0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C,
+ 0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C,
+ 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C,
+ 0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C,
+ 0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C,
+ 0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C,
+ 0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C,
+ 0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C,
+ 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C,
+ 0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C,
+ 0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C,
+ 0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C,
+ 0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C,
+ 0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C,
+ 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C,
+ 0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C,
+ 0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C,
+ 0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C,
+ 0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C,
+ 0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C,
+ 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C,
+ 0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C,
+ 0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C,
+ 0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C,
+ 0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C,
+ 0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C,
+ 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10,
+ 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10,
+ 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10,
+ 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10,
+ 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10,
+ 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10,
+ 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10,
+ 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10,
+ 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10,
+ 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10,
+ 0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF,
+ 0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF,
+ 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF,
+ 0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF,
+ 0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF,
+ 0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF,
+ 0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF,
+ 0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF,
+ 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF,
+ 0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF,
+ 0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF,
+ 0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF,
+ 0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF,
+ 0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF,
+ 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF,
+ 0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF,
+ 0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF,
+ 0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF,
+ 0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF,
+ 0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF,
+ 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF,
+ 0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF,
+ 0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF,
+ 0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF,
+ 0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF,
+ 0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF,
+ 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF,
+ 0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF,
+ 0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF,
+ 0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF,
+ 0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF,
+ 0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF,
+ 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF,
+ 0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF,
+ 0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF,
+ 0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF,
+ 0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF,
+ 0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF,
+ 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF,
+ 0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF,
+ 0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF,
+ 0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF,
+ 0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF,
+ 0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF,
+ 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF,
+ 0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF,
+ 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF,
+ 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF,
+ 0xFE, 0xFF, 0xFF, 0xFF
+};
diff --git a/drivers/staging/fbtft/fb_hx8340bn.c b/drivers/staging/fbtft/fb_hx8340bn.c
index d47dcf31fffb..2fd7b87ea0ce 100644
--- a/drivers/staging/fbtft/fb_hx8340bn.c
+++ b/drivers/staging/fbtft/fb_hx8340bn.c
@@ -151,7 +151,7 @@ static int set_var(struct fbtft_par *par)
#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
- unsigned long mask[] = {
+ static const unsigned long mask[] = {
0x0f, 0x0f, 0x1f, 0x0f, 0x0f, 0x0f, 0x1f, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x03, 0x03, 0x0f, 0x0f, 0x1f, 0x0f, 0x0f,
0x0f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00,
diff --git a/drivers/staging/fbtft/fb_hx8347d.c b/drivers/staging/fbtft/fb_hx8347d.c
index 3427a858d17c..37eaf0862c5b 100644
--- a/drivers/staging/fbtft/fb_hx8347d.c
+++ b/drivers/staging/fbtft/fb_hx8347d.c
@@ -95,7 +95,7 @@ static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
- unsigned long mask[] = {
+ static const unsigned long mask[] = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x7f, 0x7f, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x0f,
};
diff --git a/drivers/staging/fbtft/fb_ili9163.c b/drivers/staging/fbtft/fb_ili9163.c
index fd32376700e2..05648c3ffe47 100644
--- a/drivers/staging/fbtft/fb_ili9163.c
+++ b/drivers/staging/fbtft/fb_ili9163.c
@@ -195,7 +195,7 @@ static int set_var(struct fbtft_par *par)
#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
static int gamma_adj(struct fbtft_par *par, u32 *curves)
{
- unsigned long mask[] = {
+ static const unsigned long mask[] = {
0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x1f, 0x3f, 0x0f, 0x0f, 0x7f, 0x1f,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F};
diff --git a/drivers/staging/fbtft/fb_ili9320.c b/drivers/staging/fbtft/fb_ili9320.c
index ea6e001288ce..f2e72d14431d 100644
--- a/drivers/staging/fbtft/fb_ili9320.c
+++ b/drivers/staging/fbtft/fb_ili9320.c
@@ -214,7 +214,7 @@ static int set_var(struct fbtft_par *par)
#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
- unsigned long mask[] = {
+ static const unsigned long mask[] = {
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
};
diff --git a/drivers/staging/fbtft/fb_ili9325.c b/drivers/staging/fbtft/fb_ili9325.c
index 85e54a10ed72..c9aa4cb43123 100644
--- a/drivers/staging/fbtft/fb_ili9325.c
+++ b/drivers/staging/fbtft/fb_ili9325.c
@@ -208,7 +208,7 @@ static int set_var(struct fbtft_par *par)
#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
- unsigned long mask[] = {
+ static const unsigned long mask[] = {
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
};
diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c
index ad49973ad594..08f8a4bb8772 100644
--- a/drivers/staging/fbtft/fb_pcd8544.c
+++ b/drivers/staging/fbtft/fb_pcd8544.c
@@ -157,10 +157,10 @@ static struct fbtft_display display = {
.backlight = 1,
};
-FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pdc8544", &display);
+FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pcd8544", &display);
MODULE_ALIAS("spi:" DRVNAME);
-MODULE_ALIAS("spi:pdc8544");
+MODULE_ALIAS("spi:pcd8544");
MODULE_DESCRIPTION("FB driver for the PCD8544 LCD Controller");
MODULE_AUTHOR("Noralf Tronnes");
diff --git a/drivers/staging/fbtft/fb_s6d1121.c b/drivers/staging/fbtft/fb_s6d1121.c
index 5a129b1352cc..8c7de3290343 100644
--- a/drivers/staging/fbtft/fb_s6d1121.c
+++ b/drivers/staging/fbtft/fb_s6d1121.c
@@ -123,7 +123,7 @@ static int set_var(struct fbtft_par *par)
#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
- unsigned long mask[] = {
+ static const unsigned long mask[] = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
0x3f, 0x3f, 0x1f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x1f, 0x1f,
diff --git a/drivers/staging/fbtft/fb_ssd1289.c b/drivers/staging/fbtft/fb_ssd1289.c
index 88a5b6925901..7a3fe022cc69 100644
--- a/drivers/staging/fbtft/fb_ssd1289.c
+++ b/drivers/staging/fbtft/fb_ssd1289.c
@@ -129,7 +129,7 @@ static int set_var(struct fbtft_par *par)
#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
- unsigned long mask[] = {
+ static const unsigned long mask[] = {
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
};
diff --git a/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt b/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt
new file mode 100644
index 000000000000..b1f9474f36d5
--- /dev/null
+++ b/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt
@@ -0,0 +1,71 @@
+* Arcx Anybus-S controller
+
+This chip communicates with the SoC over a parallel bus. It is
+expected that its Device Tree node is specified as the child of a node
+corresponding to the parallel bus used for communication.
+
+Required properties:
+--------------------
+
+ - compatible : The following chip-specific string:
+ "arcx,anybus-controller"
+
+ - reg : three areas:
+ index 0: bus memory area where the cpld registers are located.
+ index 1: bus memory area of the first host's dual-port ram.
+ index 2: bus memory area of the second host's dual-port ram.
+
+ - reset-gpios : the GPIO pin connected to the reset line of the controller.
+
+ - interrupts : two interrupts:
+ index 0: interrupt connected to the first host
+ index 1: interrupt connected to the second host
+ Generic interrupt client node bindings are described in
+ interrupt-controller/interrupts.txt
+
+Optional: use of subnodes
+-------------------------
+
+The card connected to a host may need additional properties. These can be
+specified in subnodes to the controller node.
+
+The subnodes are identified by the standard 'reg' property. Which information
+exactly can be specified depends on the bindings for the function driver
+for the subnode.
+
+Required controller node properties when using subnodes:
+- #address-cells: should be one.
+- #size-cells: should be zero.
+
+Required subnode properties:
+- reg: Must contain the host index of the card this subnode describes:
+ <0> for the first host on the controller
+ <1> for the second host on the controller
+ Note that only a single card can be plugged into a host, so the host
+ index uniquely describes the card location.
+
+Example of usage:
+-----------------
+
+This example places the bridge on top of the i.MX WEIM parallel bus, see:
+Documentation/devicetree/bindings/bus/imx-weim.txt
+
+&weim {
+ controller@0,0 {
+ compatible = "arcx,anybus-controller";
+ reg = <0 0 0x100>, <0 0x400000 0x800>, <1 0x400000 0x800>;
+ reset-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <1 IRQ_TYPE_LEVEL_LOW>, <5 IRQ_TYPE_LEVEL_LOW>;
+ /* fsl,weim-cs-timing is a i.MX WEIM bus specific property */
+ fsl,weim-cs-timing = <0x024400b1 0x00001010 0x20081100
+ 0x00000000 0xa0000240 0x00000000>;
+ /* optional subnode for a card plugged into the first host */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ card@0 {
+ reg = <0>;
+ /* card specific properties go here */
+ };
+ };
+};
diff --git a/drivers/staging/fsl-dpaa2/ethsw/TODO b/drivers/staging/fsl-dpaa2/ethsw/TODO
index 24b5e95a96f8..4d46857b0b2b 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/TODO
+++ b/drivers/staging/fsl-dpaa2/ethsw/TODO
@@ -1,7 +1,6 @@
* Add I/O capabilities on switch port netdevices. This will allow control
traffic to reach the CPU.
* Add ACL to redirect control traffic to CPU.
-* Add support for displaying learned FDB entries
* Add support for multiple FDBs and switch port partitioning
* MC firmware uprev; the DPAA2 objects used by the Ethernet Switch driver
need to be kept in sync with binary interface changes in MC
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index 14b974defa3a..5e1339daa7c7 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -10,7 +10,7 @@
/* DPSW Version */
#define DPSW_VER_MAJOR 8
-#define DPSW_VER_MINOR 0
+#define DPSW_VER_MINOR 1
#define DPSW_CMD_BASE_VERSION 1
#define DPSW_CMD_ID_OFFSET 4
@@ -67,6 +67,7 @@
#define DPSW_CMDID_FDB_ADD_MULTICAST DPSW_CMD_ID(0x086)
#define DPSW_CMDID_FDB_REMOVE_MULTICAST DPSW_CMD_ID(0x087)
#define DPSW_CMDID_FDB_SET_LEARNING_MODE DPSW_CMD_ID(0x088)
+#define DPSW_CMDID_FDB_DUMP DPSW_CMD_ID(0x08A)
/* Macros for accessing command fields smaller than 1byte */
#define DPSW_MASK(field) \
@@ -351,6 +352,18 @@ struct dpsw_cmd_fdb_set_learning_mode {
u8 mode;
};
+struct dpsw_cmd_fdb_dump {
+ __le16 fdb_id;
+ __le16 pad0;
+ __le32 pad1;
+ __le64 iova_addr;
+ __le32 iova_size;
+};
+
+struct dpsw_rsp_fdb_dump {
+ __le16 num_entries;
+};
+
struct dpsw_rsp_get_api_version {
__le16 version_major;
__le16 version_minor;
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
index cabed77b445d..56b0fa789a67 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -981,6 +981,57 @@ int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io,
}
/**
+ * dpsw_fdb_dump() - Dump the content of FDB table into memory.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @fdb_id: Forwarding Database Identifier
+ * @iova_addr: Data will be stored here as an array of struct fdb_dump_entry
+ * @iova_size: Memory size allocated at iova_addr
+ * @num_entries:Number of entries written at iova_addr
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ *
+ * The memory allocated at iova_addr must be initialized with zero before
+ * command execution. If the FDB table does not fit into memory MC will stop
+ * after the memory is filled up.
+ * The struct fdb_dump_entry array must be parsed until the end of memory
+ * area or until an entry with mac_addr set to zero is found.
+ */
+int dpsw_fdb_dump(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ u64 iova_addr,
+ u32 iova_size,
+ u16 *num_entries)
+{
+ struct dpsw_cmd_fdb_dump *cmd_params;
+ struct dpsw_rsp_fdb_dump *rsp_params;
+ struct fsl_mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_DUMP,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_fdb_dump *)cmd.params;
+ cmd_params->fdb_id = cpu_to_le16(fdb_id);
+ cmd_params->iova_addr = cpu_to_le64(iova_addr);
+ cmd_params->iova_size = cpu_to_le32(iova_size);
+
+ /* send command to mc */
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dpsw_rsp_fdb_dump *)cmd.params;
+ *num_entries = le16_to_cpu(rsp_params->num_entries);
+
+ return 0;
+}
+
+/**
* dpsw_fdb_remove_unicast() - removes an entry from MAC lookup table
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index 25635259ce44..25b45850925c 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -75,37 +75,6 @@ enum dpsw_component_type {
DPSW_COMPONENT_TYPE_S_VLAN
};
-/**
- * struct dpsw_cfg - DPSW configuration
- * @num_ifs: Number of external and internal interfaces
- * @adv: Advanced parameters; default is all zeros;
- * use this structure to change default settings
- * @adv.options: Enable/Disable DPSW features (bitmap)
- * @adv.max_vlans: Maximum Number of VLAN's; 0 - indicates default 16
- * @adv.max_meters_per_if: Number of meters per interface
- * @adv.max_fdbs: Maximum Number of FDB's; 0 - indicates default 16
- * @adv.max_fdb_entries: Number of FDB entries for default FDB table;
- * 0 - indicates default 1024 entries.
- * @adv.fdb_aging_time: Default FDB aging time for default FDB table;
- * 0 - indicates default 300 seconds
- * @adv.max_fdb_mc_groups: Number of multicast groups in each FDB table;
- * 0 - indicates default 32
- * @adv.component_type: Indicates the component type of this bridge
- */
-struct dpsw_cfg {
- u16 num_ifs;
- struct {
- u64 options;
- u16 max_vlans;
- u8 max_meters_per_if;
- u8 max_fdbs;
- u16 max_fdb_entries;
- u16 fdb_aging_time;
- u16 max_fdb_mc_groups;
- enum dpsw_component_type component_type;
- } adv;
-};
-
int dpsw_enable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token);
@@ -496,6 +465,31 @@ int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io,
u16 fdb_id,
const struct dpsw_fdb_unicast_cfg *cfg);
+#define DPSW_FDB_ENTRY_TYPE_DYNAMIC BIT(0)
+#define DPSW_FDB_ENTRY_TYPE_UNICAST BIT(1)
+
+/**
+ * struct fdb_dump_entry - fdb snapshot entry
+ * @mac_addr: MAC address
+ * @type: bit0 - DINAMIC(1)/STATIC(0), bit1 - UNICAST(1)/MULTICAST(0)
+ * @if_info: unicast - egress interface, multicast - number of egress interfaces
+ * @if_mask: multicast - egress interface mask
+ */
+struct fdb_dump_entry {
+ u8 mac_addr[6];
+ u8 type;
+ u8 if_info;
+ u8 if_mask[8];
+};
+
+int dpsw_fdb_dump(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ u64 iova_addr,
+ u32 iova_size,
+ u16 *num_entries);
+
/**
* struct dpsw_fdb_multicast_cfg - Multi-cast entry configuration
* @type: Select static or dynamic entry
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c
index 926a0c053e18..4f0bff86e43e 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c
@@ -65,7 +65,7 @@ ethsw_get_link_ksettings(struct net_device *netdev,
port_priv->idx,
&state);
if (err) {
- netdev_err(netdev, "ERROR %d getting link state", err);
+ netdev_err(netdev, "ERROR %d getting link state\n", err);
goto out;
}
@@ -88,18 +88,21 @@ ethsw_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *link_ksettings)
{
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
struct dpsw_link_cfg cfg = {0};
- int err = 0;
-
- netdev_dbg(netdev, "Setting link parameters...");
-
- /* Due to a temporary MC limitation, the DPSW port must be down
- * in order to be able to change link settings. Taking steps to let
- * the user know that.
- */
- if (netif_running(netdev)) {
- netdev_info(netdev, "Sorry, interface must be brought down first.\n");
- return -EACCES;
+ bool if_running;
+ int err = 0, ret;
+
+ /* Interface needs to be down to change link settings */
+ if_running = netif_running(netdev);
+ if (if_running) {
+ err = dpsw_if_disable(ethsw->mc_io, 0,
+ ethsw->dpsw_handle,
+ port_priv->idx);
+ if (err) {
+ netdev_err(netdev, "dpsw_if_disable err %d\n", err);
+ return err;
+ }
}
cfg.rate = link_ksettings->base.speed;
@@ -116,12 +119,16 @@ ethsw_set_link_ksettings(struct net_device *netdev,
port_priv->ethsw_data->dpsw_handle,
port_priv->idx,
&cfg);
- if (err)
- /* ethtool will be loud enough if we return an error; no point
- * in putting our own error message on the console by default
- */
- netdev_dbg(netdev, "ERROR %d setting link cfg", err);
+ if (if_running) {
+ ret = dpsw_if_enable(ethsw->mc_io, 0,
+ ethsw->dpsw_handle,
+ port_priv->idx);
+ if (ret) {
+ netdev_err(netdev, "dpsw_if_enable err %d\n", ret);
+ return ret;
+ }
+ }
return err;
}
@@ -156,9 +163,6 @@ static void ethsw_ethtool_get_stats(struct net_device *netdev,
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
int i, err;
- memset(data, 0,
- sizeof(u64) * ETHSW_NUM_COUNTERS);
-
for (i = 0; i < ETHSW_NUM_COUNTERS; i++) {
err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
port_priv->ethsw_data->dpsw_handle,
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index f73edaf6ce87..14a9eebf687e 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -22,7 +22,7 @@ static struct workqueue_struct *ethsw_owq;
/* Minimal supported DPSW version */
#define DPSW_MIN_VER_MAJOR 8
-#define DPSW_MIN_VER_MINOR 0
+#define DPSW_MIN_VER_MINOR 1
#define DEFAULT_VLAN_ID 1
@@ -34,11 +34,6 @@ static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid)
.fdb_id = 0,
};
- if (ethsw->vlans[vid]) {
- dev_err(ethsw->dev, "VLAN already configured\n");
- return -EEXIST;
- }
-
err = dpsw_vlan_add(ethsw->mc_io, 0,
ethsw->dpsw_handle, vid, &vcfg);
if (err) {
@@ -149,12 +144,12 @@ static int ethsw_port_add_vlan(struct ethsw_port_priv *port_priv,
return 0;
}
-static int ethsw_set_learning(struct ethsw_core *ethsw, u8 flag)
+static int ethsw_set_learning(struct ethsw_core *ethsw, bool enable)
{
enum dpsw_fdb_learning_mode learn_mode;
int err;
- if (flag)
+ if (enable)
learn_mode = DPSW_FDB_LEARNING_MODE_HW;
else
learn_mode = DPSW_FDB_LEARNING_MODE_DIS;
@@ -165,24 +160,24 @@ static int ethsw_set_learning(struct ethsw_core *ethsw, u8 flag)
dev_err(ethsw->dev, "dpsw_fdb_set_learning_mode err %d\n", err);
return err;
}
- ethsw->learning = !!flag;
+ ethsw->learning = enable;
return 0;
}
-static int ethsw_port_set_flood(struct ethsw_port_priv *port_priv, u8 flag)
+static int ethsw_port_set_flood(struct ethsw_port_priv *port_priv, bool enable)
{
int err;
err = dpsw_if_set_flooding(port_priv->ethsw_data->mc_io, 0,
port_priv->ethsw_data->dpsw_handle,
- port_priv->idx, flag);
+ port_priv->idx, enable);
if (err) {
netdev_err(port_priv->netdev,
"dpsw_if_set_flooding err %d\n", err);
return err;
}
- port_priv->flood = !!flag;
+ port_priv->flood = enable;
return 0;
}
@@ -316,6 +311,31 @@ static int ethsw_port_fdb_del_mc(struct ethsw_port_priv *port_priv,
return err;
}
+static int port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+ struct net_device *dev, const unsigned char *addr,
+ u16 vid, u16 flags,
+ struct netlink_ext_ack *extack)
+{
+ if (is_unicast_ether_addr(addr))
+ return ethsw_port_fdb_add_uc(netdev_priv(dev),
+ addr);
+ else
+ return ethsw_port_fdb_add_mc(netdev_priv(dev),
+ addr);
+}
+
+static int port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr, u16 vid)
+{
+ if (is_unicast_ether_addr(addr))
+ return ethsw_port_fdb_del_uc(netdev_priv(dev),
+ addr);
+ else
+ return ethsw_port_fdb_del_mc(netdev_priv(dev),
+ addr);
+}
+
static void port_get_stats(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
@@ -516,17 +536,165 @@ static int swdev_get_port_parent_id(struct net_device *dev,
return 0;
}
+static int port_get_phys_name(struct net_device *netdev, char *name,
+ size_t len)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int err;
+
+ err = snprintf(name, len, "p%d", port_priv->idx);
+ if (err >= len)
+ return -EINVAL;
+
+ return 0;
+}
+
+struct ethsw_dump_ctx {
+ struct net_device *dev;
+ struct sk_buff *skb;
+ struct netlink_callback *cb;
+ int idx;
+};
+
+static int ethsw_fdb_do_dump(struct fdb_dump_entry *entry,
+ struct ethsw_dump_ctx *dump)
+{
+ int is_dynamic = entry->type & DPSW_FDB_ENTRY_DINAMIC;
+ u32 portid = NETLINK_CB(dump->cb->skb).portid;
+ u32 seq = dump->cb->nlh->nlmsg_seq;
+ struct nlmsghdr *nlh;
+ struct ndmsg *ndm;
+
+ if (dump->idx < dump->cb->args[2])
+ goto skip;
+
+ nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
+ sizeof(*ndm), NLM_F_MULTI);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ ndm = nlmsg_data(nlh);
+ ndm->ndm_family = AF_BRIDGE;
+ ndm->ndm_pad1 = 0;
+ ndm->ndm_pad2 = 0;
+ ndm->ndm_flags = NTF_SELF;
+ ndm->ndm_type = 0;
+ ndm->ndm_ifindex = dump->dev->ifindex;
+ ndm->ndm_state = is_dynamic ? NUD_REACHABLE : NUD_NOARP;
+
+ if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, entry->mac_addr))
+ goto nla_put_failure;
+
+ nlmsg_end(dump->skb, nlh);
+
+skip:
+ dump->idx++;
+ return 0;
+
+nla_put_failure:
+ nlmsg_cancel(dump->skb, nlh);
+ return -EMSGSIZE;
+}
+
+static int port_fdb_valid_entry(struct fdb_dump_entry *entry,
+ struct ethsw_port_priv *port_priv)
+{
+ int idx = port_priv->idx;
+ int valid;
+
+ if (entry->type & DPSW_FDB_ENTRY_TYPE_UNICAST)
+ valid = entry->if_info == port_priv->idx;
+ else
+ valid = entry->if_mask[idx / 8] & BIT(idx % 8);
+
+ return valid;
+}
+
+static int port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
+ struct net_device *net_dev,
+ struct net_device *filter_dev, int *idx)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(net_dev);
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct device *dev = net_dev->dev.parent;
+ struct fdb_dump_entry *fdb_entries;
+ struct fdb_dump_entry fdb_entry;
+ struct ethsw_dump_ctx dump = {
+ .dev = net_dev,
+ .skb = skb,
+ .cb = cb,
+ .idx = *idx,
+ };
+ dma_addr_t fdb_dump_iova;
+ u16 num_fdb_entries;
+ u32 fdb_dump_size;
+ int err = 0, i;
+ u8 *dma_mem;
+
+ fdb_dump_size = ethsw->sw_attr.max_fdb_entries * sizeof(fdb_entry);
+ dma_mem = kzalloc(fdb_dump_size, GFP_KERNEL);
+ if (!dma_mem)
+ return -ENOMEM;
+
+ fdb_dump_iova = dma_map_single(dev, dma_mem, fdb_dump_size,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, fdb_dump_iova)) {
+ netdev_err(net_dev, "dma_map_single() failed\n");
+ err = -ENOMEM;
+ goto err_map;
+ }
+
+ err = dpsw_fdb_dump(ethsw->mc_io, 0, ethsw->dpsw_handle, 0,
+ fdb_dump_iova, fdb_dump_size, &num_fdb_entries);
+ if (err) {
+ netdev_err(net_dev, "dpsw_fdb_dump() = %d\n", err);
+ goto err_dump;
+ }
+
+ dma_unmap_single(dev, fdb_dump_iova, fdb_dump_size, DMA_FROM_DEVICE);
+
+ fdb_entries = (struct fdb_dump_entry *)dma_mem;
+ for (i = 0; i < num_fdb_entries; i++) {
+ fdb_entry = fdb_entries[i];
+
+ if (!port_fdb_valid_entry(&fdb_entry, port_priv))
+ continue;
+
+ err = ethsw_fdb_do_dump(&fdb_entry, &dump);
+ if (err)
+ goto end;
+ }
+
+end:
+ *idx = dump.idx;
+
+ kfree(dma_mem);
+
+ return 0;
+
+err_dump:
+ dma_unmap_single(dev, fdb_dump_iova, fdb_dump_size, DMA_TO_DEVICE);
+err_map:
+ kfree(dma_mem);
+ return err;
+}
+
static const struct net_device_ops ethsw_port_ops = {
.ndo_open = port_open,
.ndo_stop = port_stop,
.ndo_set_mac_address = eth_mac_addr,
+ .ndo_get_stats64 = port_get_stats,
.ndo_change_mtu = port_change_mtu,
.ndo_has_offload_stats = port_has_offload_stats,
.ndo_get_offload_stats = port_get_offload_stats,
+ .ndo_fdb_add = port_fdb_add,
+ .ndo_fdb_del = port_fdb_del,
+ .ndo_fdb_dump = port_fdb_dump,
.ndo_start_xmit = port_dropframe,
.ndo_get_port_parent_id = swdev_get_port_parent_id,
+ .ndo_get_phys_port_name = port_get_phys_name,
};
static void ethsw_links_state_update(struct ethsw_core *ethsw)
@@ -549,12 +717,12 @@ static irqreturn_t ethsw_irq0_handler_thread(int irq_num, void *arg)
err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, &status);
if (err) {
- dev_err(dev, "Can't get irq status (err %d)", err);
+ dev_err(dev, "Can't get irq status (err %d)\n", err);
err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, 0xFFFFFFFF);
if (err)
- dev_err(dev, "Can't clear irq status (err %d)", err);
+ dev_err(dev, "Can't clear irq status (err %d)\n", err);
goto out;
}
@@ -599,21 +767,21 @@ static int ethsw_setup_irqs(struct fsl_mc_device *sw_dev)
IRQF_NO_SUSPEND | IRQF_ONESHOT,
dev_name(dev), dev);
if (err) {
- dev_err(dev, "devm_request_threaded_irq(): %d", err);
+ dev_err(dev, "devm_request_threaded_irq(): %d\n", err);
goto free_irq;
}
err = dpsw_set_irq_mask(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, mask);
if (err) {
- dev_err(dev, "dpsw_set_irq_mask(): %d", err);
+ dev_err(dev, "dpsw_set_irq_mask(): %d\n", err);
goto free_devm_irq;
}
err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, 1);
if (err) {
- dev_err(dev, "dpsw_set_irq_enable(): %d", err);
+ dev_err(dev, "dpsw_set_irq_enable(): %d\n", err);
goto free_devm_irq;
}
@@ -673,11 +841,12 @@ static int port_attr_br_flags_set(struct net_device *netdev,
return 0;
/* Learning is enabled per switch */
- err = ethsw_set_learning(port_priv->ethsw_data, flags & BR_LEARNING);
+ err = ethsw_set_learning(port_priv->ethsw_data,
+ !!(flags & BR_LEARNING));
if (err)
goto exit;
- err = ethsw_port_set_flood(port_priv, flags & BR_FLOOD);
+ err = ethsw_port_set_flood(port_priv, !!(flags & BR_FLOOD));
exit:
return err;
@@ -950,8 +1119,7 @@ static int port_bridge_join(struct net_device *netdev,
if (ethsw->ports[i]->bridge_dev &&
(ethsw->ports[i]->bridge_dev != upper_dev)) {
netdev_err(netdev,
- "Another switch port is connected to %s\n",
- ethsw->ports[i]->bridge_dev->name);
+ "Only one bridge supported per DPSW object!\n");
return -EINVAL;
}
@@ -1023,18 +1191,30 @@ static void ethsw_switchdev_event_work(struct work_struct *work)
container_of(work, struct ethsw_switchdev_event_work, work);
struct net_device *dev = switchdev_work->dev;
struct switchdev_notifier_fdb_info *fdb_info;
+ int err;
rtnl_lock();
fdb_info = &switchdev_work->fdb_info;
switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ if (!fdb_info->added_by_user)
+ break;
if (is_unicast_ether_addr(fdb_info->addr))
- ethsw_port_fdb_add_uc(netdev_priv(dev), fdb_info->addr);
+ err = ethsw_port_fdb_add_uc(netdev_priv(dev),
+ fdb_info->addr);
else
- ethsw_port_fdb_add_mc(netdev_priv(dev), fdb_info->addr);
+ err = ethsw_port_fdb_add_mc(netdev_priv(dev),
+ fdb_info->addr);
+ if (err)
+ break;
+ fdb_info->offloaded = true;
+ call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev,
+ &fdb_info->info, NULL);
break;
case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ if (!fdb_info->added_by_user)
+ break;
if (is_unicast_ether_addr(fdb_info->addr))
ethsw_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr);
else
@@ -1177,48 +1357,6 @@ err_switchdev_nb:
return err;
}
-static int ethsw_open(struct ethsw_core *ethsw)
-{
- struct ethsw_port_priv *port_priv = NULL;
- int i, err;
-
- err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle);
- if (err) {
- dev_err(ethsw->dev, "dpsw_enable err %d\n", err);
- return err;
- }
-
- for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
- port_priv = ethsw->ports[i];
- err = dev_open(port_priv->netdev, NULL);
- if (err) {
- netdev_err(port_priv->netdev, "dev_open err %d\n", err);
- return err;
- }
- }
-
- return 0;
-}
-
-static int ethsw_stop(struct ethsw_core *ethsw)
-{
- struct ethsw_port_priv *port_priv = NULL;
- int i, err;
-
- for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
- port_priv = ethsw->ports[i];
- dev_close(port_priv->netdev);
- }
-
- err = dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle);
- if (err) {
- dev_err(ethsw->dev, "dpsw_disable err %d\n", err);
- return err;
- }
-
- return 0;
-}
-
static int ethsw_init(struct fsl_mc_device *sw_dev)
{
struct device *dev = &sw_dev->dev;
@@ -1320,7 +1458,6 @@ err_close:
static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
{
- const char def_mcast[ETH_ALEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01};
struct net_device *netdev = port_priv->netdev;
struct ethsw_core *ethsw = port_priv->ethsw_data;
struct dpsw_vlan_if_cfg vcfg;
@@ -1346,12 +1483,10 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle,
DEFAULT_VLAN_ID, &vcfg);
- if (err) {
+ if (err)
netdev_err(netdev, "dpsw_vlan_remove_if err %d\n", err);
- return err;
- }
- return ethsw_port_fdb_add_mc(port_priv, def_mcast);
+ return err;
}
static void ethsw_unregister_notifier(struct device *dev)
@@ -1403,9 +1538,7 @@ static int ethsw_remove(struct fsl_mc_device *sw_dev)
destroy_workqueue(ethsw_owq);
- rtnl_lock();
- ethsw_stop(ethsw);
- rtnl_unlock();
+ dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle);
for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
port_priv = ethsw->ports[i];
@@ -1455,16 +1588,24 @@ static int ethsw_probe_port(struct ethsw_core *ethsw, u16 port_idx)
port_netdev->min_mtu = ETH_MIN_MTU;
port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH;
+ err = ethsw_port_init(port_priv, port_idx);
+ if (err)
+ goto err_port_probe;
+
err = register_netdev(port_netdev);
if (err < 0) {
dev_err(dev, "register_netdev error %d\n", err);
- free_netdev(port_netdev);
- return err;
+ goto err_port_probe;
}
ethsw->ports[port_idx] = port_priv;
- return ethsw_port_init(port_priv, port_idx);
+ return 0;
+
+err_port_probe:
+ free_netdev(port_netdev);
+
+ return err;
}
static int ethsw_probe(struct fsl_mc_device *sw_dev)
@@ -1482,7 +1623,8 @@ static int ethsw_probe(struct fsl_mc_device *sw_dev)
ethsw->dev = dev;
dev_set_drvdata(dev, ethsw);
- err = fsl_mc_portal_allocate(sw_dev, 0, &ethsw->mc_io);
+ err = fsl_mc_portal_allocate(sw_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
+ &ethsw->mc_io);
if (err) {
if (err == -ENXIO)
err = -EPROBE_DEFER;
@@ -1514,12 +1656,11 @@ static int ethsw_probe(struct fsl_mc_device *sw_dev)
goto err_free_ports;
}
- /* Switch starts up enabled */
- rtnl_lock();
- err = ethsw_open(ethsw);
- rtnl_unlock();
- if (err)
+ err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle);
+ if (err) {
+ dev_err(ethsw->dev, "dpsw_enable err %d\n", err);
goto err_free_ports;
+ }
/* Setup IRQs */
err = ethsw_setup_irqs(sw_dev);
@@ -1530,9 +1671,7 @@ static int ethsw_probe(struct fsl_mc_device *sw_dev)
return 0;
err_stop:
- rtnl_lock();
- ethsw_stop(ethsw);
- rtnl_unlock();
+ dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle);
err_free_ports:
/* Cleanup registered ports only */
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index c48783680a05..3ea8a0ad8c10 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -23,9 +23,13 @@
/* Number of IRQs supported */
#define DPSW_IRQ_NUM 2
+/* Port is member of VLAN */
#define ETHSW_VLAN_MEMBER 1
+/* VLAN to be treated as untagged on egress */
#define ETHSW_VLAN_UNTAGGED 2
+/* Untagged frames will be assigned to this VLAN */
#define ETHSW_VLAN_PVID 4
+/* VLAN configured on the switch */
#define ETHSW_VLAN_GLOBAL 8
/* Maximum Frame Length supported by HW (currently 10k) */
diff --git a/drivers/staging/gasket/apex_driver.c b/drivers/staging/gasket/apex_driver.c
index 464648ee2036..46199c8ca441 100644
--- a/drivers/staging/gasket/apex_driver.c
+++ b/drivers/staging/gasket/apex_driver.c
@@ -509,6 +509,8 @@ static ssize_t sysfs_show(struct device *device, struct device_attribute *attr,
struct gasket_dev *gasket_dev;
struct gasket_sysfs_attribute *gasket_attr;
enum sysfs_attribute_type type;
+ struct gasket_page_table *gpt;
+ uint val;
gasket_dev = gasket_sysfs_get_device_data(device);
if (!gasket_dev) {
@@ -524,29 +526,25 @@ static ssize_t sysfs_show(struct device *device, struct device_attribute *attr,
}
type = (enum sysfs_attribute_type)gasket_attr->data.attr_type;
+ gpt = gasket_dev->page_table[0];
switch (type) {
case ATTR_KERNEL_HIB_PAGE_TABLE_SIZE:
- ret = scnprintf(buf, PAGE_SIZE, "%u\n",
- gasket_page_table_num_entries(
- gasket_dev->page_table[0]));
+ val = gasket_page_table_num_entries(gpt);
break;
case ATTR_KERNEL_HIB_SIMPLE_PAGE_TABLE_SIZE:
- ret = scnprintf(buf, PAGE_SIZE, "%u\n",
- gasket_page_table_num_simple_entries(
- gasket_dev->page_table[0]));
+ val = gasket_page_table_num_simple_entries(gpt);
break;
case ATTR_KERNEL_HIB_NUM_ACTIVE_PAGES:
- ret = scnprintf(buf, PAGE_SIZE, "%u\n",
- gasket_page_table_num_active_pages(
- gasket_dev->page_table[0]));
+ val = gasket_page_table_num_active_pages(gpt);
break;
default:
dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n",
attr->attr.name);
ret = 0;
- break;
+ goto exit;
}
-
+ ret = scnprintf(buf, PAGE_SIZE, "%u\n", val);
+exit:
gasket_sysfs_put_attr(device, gasket_attr);
gasket_sysfs_put_device_data(device, gasket_dev);
return ret;
@@ -659,7 +657,7 @@ static void apex_pci_remove(struct pci_dev *pci_dev)
pci_disable_device(pci_dev);
}
-static struct gasket_driver_desc apex_desc = {
+static const struct gasket_driver_desc apex_desc = {
.name = "apex",
.driver_version = APEX_DRIVER_VERSION,
.major = 120,
diff --git a/drivers/staging/gasket/gasket_ioctl.c b/drivers/staging/gasket/gasket_ioctl.c
index 7ecfba4f2b06..240f9bb10b71 100644
--- a/drivers/staging/gasket/gasket_ioctl.c
+++ b/drivers/staging/gasket/gasket_ioctl.c
@@ -39,8 +39,7 @@ static int gasket_set_event_fd(struct gasket_dev *gasket_dev,
}
/* Read the size of the page table. */
-static int gasket_read_page_table_size(
- struct gasket_dev *gasket_dev,
+static int gasket_read_page_table_size(struct gasket_dev *gasket_dev,
struct gasket_page_table_ioctl __user *argp)
{
int ret = 0;
@@ -66,8 +65,7 @@ static int gasket_read_page_table_size(
}
/* Read the size of the simple page table. */
-static int gasket_read_simple_page_table_size(
- struct gasket_dev *gasket_dev,
+static int gasket_read_simple_page_table_size(struct gasket_dev *gasket_dev,
struct gasket_page_table_ioctl __user *argp)
{
int ret = 0;
@@ -93,8 +91,7 @@ static int gasket_read_simple_page_table_size(
}
/* Set the boundary between the simple and extended page tables. */
-static int gasket_partition_page_table(
- struct gasket_dev *gasket_dev,
+static int gasket_partition_page_table(struct gasket_dev *gasket_dev,
struct gasket_page_table_ioctl __user *argp)
{
int ret;
@@ -185,8 +182,7 @@ static int gasket_unmap_buffers(struct gasket_dev *gasket_dev,
* Reserve structures for coherent allocation, and allocate or free the
* corresponding memory.
*/
-static int gasket_config_coherent_allocator(
- struct gasket_dev *gasket_dev,
+static int gasket_config_coherent_allocator(struct gasket_dev *gasket_dev,
struct gasket_coherent_alloc_config_ioctl __user *argp)
{
int ret;
diff --git a/drivers/staging/goldfish/goldfish_audio.c b/drivers/staging/goldfish/goldfish_audio.c
index 24a738238f9f..0c65a0121dde 100644
--- a/drivers/staging/goldfish/goldfish_audio.c
+++ b/drivers/staging/goldfish/goldfish_audio.c
@@ -302,10 +302,8 @@ static int goldfish_audio_probe(struct platform_device *pdev)
return -ENOMEM;
data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0) {
- dev_err(&pdev->dev, "platform_get_irq failed\n");
+ if (data->irq < 0)
return -ENODEV;
- }
data->buffer_virt = dmam_alloc_coherent(&pdev->dev,
COMBINED_BUFFER_SIZE,
&buf_addr, GFP_KERNEL);
diff --git a/drivers/staging/greybus/Documentation/firmware/authenticate.c b/drivers/staging/greybus/Documentation/firmware/authenticate.c
index 806e75b7f405..3d2c6f88a138 100644
--- a/drivers/staging/greybus/Documentation/firmware/authenticate.c
+++ b/drivers/staging/greybus/Documentation/firmware/authenticate.c
@@ -2,54 +2,8 @@
/*
* Sample code to test CAP protocol
*
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
* Copyright(c) 2016 Google Inc. All rights reserved.
* Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 for more details.
- *
- * BSD LICENSE
- *
- * Copyright(c) 2016 Google Inc. All rights reserved.
- * Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
- * its contributors may be used to endorse or promote products
- * derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
- * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
diff --git a/drivers/staging/greybus/Documentation/firmware/firmware.c b/drivers/staging/greybus/Documentation/firmware/firmware.c
index 31d9c23e2eeb..765d69faa9cc 100644
--- a/drivers/staging/greybus/Documentation/firmware/firmware.c
+++ b/drivers/staging/greybus/Documentation/firmware/firmware.c
@@ -2,54 +2,8 @@
/*
* Sample code to test firmware-management protocol
*
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
* Copyright(c) 2016 Google Inc. All rights reserved.
* Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 for more details.
- *
- * BSD LICENSE
- *
- * Copyright(c) 2016 Google Inc. All rights reserved.
- * Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
- * its contributors may be used to endorse or promote products
- * derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
- * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
diff --git a/drivers/staging/greybus/Kconfig b/drivers/staging/greybus/Kconfig
index 4894c3514955..d4777f5a8b90 100644
--- a/drivers/staging/greybus/Kconfig
+++ b/drivers/staging/greybus/Kconfig
@@ -1,33 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-menuconfig GREYBUS
- tristate "Greybus support"
- depends on SYSFS
- ---help---
- This option enables the Greybus driver core. Greybus is an
- hardware protocol that was designed to provide Unipro with a
- sane application layer. It was originally designed for the
- ARA project, a module phone system, but has shown up in other
- phones, and can be tunneled over other busses in order to
- control hardware devices.
-
- Say Y here to enable support for these types of drivers.
-
- To compile this code as a module, chose M here: the module
- will be called greybus.ko
-
if GREYBUS
-config GREYBUS_ES2
- tristate "Greybus ES3 USB host controller"
- depends on USB
- ---help---
- Select this option if you have a Toshiba ES3 USB device that
- acts as a Greybus "host controller". This device is a bridge
- from a USB device to a Unipro network.
-
- To compile this code as a module, chose M here: the module
- will be called gb-es2.ko
-
config GREYBUS_AUDIO
tristate "Greybus Audio Class driver"
depends on SOUND
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile
index 2551ed16b742..627e44f2a983 100644
--- a/drivers/staging/greybus/Makefile
+++ b/drivers/staging/greybus/Makefile
@@ -1,29 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
-# Greybus core
-greybus-y := core.o \
- debugfs.o \
- hd.o \
- manifest.o \
- module.o \
- interface.o \
- bundle.o \
- connection.o \
- control.o \
- svc.o \
- svc_watchdog.o \
- operation.o
-
-obj-$(CONFIG_GREYBUS) += greybus.o
-
# needed for trace events
ccflags-y += -I$(src)
-
-# Greybus Host controller drivers
-gb-es2-y := es2.o
-
-obj-$(CONFIG_GREYBUS_ES2) += gb-es2.o
-
# Greybus class drivers
gb-bootrom-y := bootrom.o
gb-camera-y := camera.o
diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c
index 6eb842040c22..eebf0deb39f5 100644
--- a/drivers/staging/greybus/arche-platform.c
+++ b/drivers/staging/greybus/arche-platform.c
@@ -19,8 +19,8 @@
#include <linux/irq.h>
#include <linux/suspend.h>
#include <linux/time.h>
+#include <linux/greybus.h>
#include "arche_platform.h"
-#include "greybus.h"
#if IS_ENABLED(CONFIG_USB_HSIC_USB3613)
#include <linux/usb/usb3613.h>
diff --git a/drivers/staging/greybus/arpc.h b/drivers/staging/greybus/arpc.h
deleted file mode 100644
index 3dab6375909c..000000000000
--- a/drivers/staging/greybus/arpc.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
-/*
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2016 Google Inc. All rights reserved.
- * Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 for more details.
- *
- * BSD LICENSE
- *
- * Copyright(c) 2016 Google Inc. All rights reserved.
- * Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
- * its contributors may be used to endorse or promote products
- * derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
- * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __ARPC_H
-#define __ARPC_H
-
-/* APBridgeA RPC (ARPC) */
-
-enum arpc_result {
- ARPC_SUCCESS = 0x00,
- ARPC_NO_MEMORY = 0x01,
- ARPC_INVALID = 0x02,
- ARPC_TIMEOUT = 0x03,
- ARPC_UNKNOWN_ERROR = 0xff,
-};
-
-struct arpc_request_message {
- __le16 id; /* RPC unique id */
- __le16 size; /* Size in bytes of header + payload */
- __u8 type; /* RPC type */
- __u8 data[0]; /* ARPC data */
-} __packed;
-
-struct arpc_response_message {
- __le16 id; /* RPC unique id */
- __u8 result; /* Result of RPC */
-} __packed;
-
-/* ARPC requests */
-#define ARPC_TYPE_CPORT_CONNECTED 0x01
-#define ARPC_TYPE_CPORT_QUIESCE 0x02
-#define ARPC_TYPE_CPORT_CLEAR 0x03
-#define ARPC_TYPE_CPORT_FLUSH 0x04
-#define ARPC_TYPE_CPORT_SHUTDOWN 0x05
-
-struct arpc_cport_connected_req {
- __le16 cport_id;
-} __packed;
-
-struct arpc_cport_quiesce_req {
- __le16 cport_id;
- __le16 peer_space;
- __le16 timeout;
-} __packed;
-
-struct arpc_cport_clear_req {
- __le16 cport_id;
-} __packed;
-
-struct arpc_cport_flush_req {
- __le16 cport_id;
-} __packed;
-
-struct arpc_cport_shutdown_req {
- __le16 cport_id;
- __le16 timeout;
- __u8 phase;
-} __packed;
-
-#endif /* __ARPC_H */
diff --git a/drivers/staging/greybus/audio_apbridgea.c b/drivers/staging/greybus/audio_apbridgea.c
index 7ebb1bde5cb7..26117e390deb 100644
--- a/drivers/staging/greybus/audio_apbridgea.c
+++ b/drivers/staging/greybus/audio_apbridgea.c
@@ -5,8 +5,7 @@
* Copyright 2015-2016 Google Inc.
*/
-#include "greybus.h"
-#include "greybus_protocols.h"
+#include <linux/greybus.h>
#include "audio_apbridgea.h"
#include "audio_codec.h"
diff --git a/drivers/staging/greybus/audio_apbridgea.h b/drivers/staging/greybus/audio_apbridgea.h
index 330fc7a397eb..3f1f4dd2c61a 100644
--- a/drivers/staging/greybus/audio_apbridgea.h
+++ b/drivers/staging/greybus/audio_apbridgea.h
@@ -1,30 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
-/**
+/*
* Copyright (c) 2015-2016 Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This is a special protocol for configuring communication over the
diff --git a/drivers/staging/greybus/audio_codec.h b/drivers/staging/greybus/audio_codec.h
index 9ba09ea9c2fc..cb5d271da1a5 100644
--- a/drivers/staging/greybus/audio_codec.h
+++ b/drivers/staging/greybus/audio_codec.h
@@ -8,12 +8,10 @@
#ifndef __LINUX_GBAUDIO_CODEC_H
#define __LINUX_GBAUDIO_CODEC_H
+#include <linux/greybus.h>
#include <sound/soc.h>
#include <sound/jack.h>
-#include "greybus.h"
-#include "greybus_protocols.h"
-
#define NAME_SIZE 32
#define MAX_DAIS 2 /* APB1, APB2 */
diff --git a/drivers/staging/greybus/audio_gb.c b/drivers/staging/greybus/audio_gb.c
index 8894f1c87d48..9d8994fdb41a 100644
--- a/drivers/staging/greybus/audio_gb.c
+++ b/drivers/staging/greybus/audio_gb.c
@@ -5,9 +5,7 @@
* Copyright 2015-2016 Google Inc.
*/
-#include "greybus.h"
-#include "greybus_protocols.h"
-#include "operation.h"
+#include <linux/greybus.h>
#include "audio_codec.h"
/* TODO: Split into separate calls */
diff --git a/drivers/staging/greybus/audio_manager.c b/drivers/staging/greybus/audio_manager.c
index c2a4af4c1d06..9b19ea9d3fa1 100644
--- a/drivers/staging/greybus/audio_manager.c
+++ b/drivers/staging/greybus/audio_manager.c
@@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(gb_audio_manager_remove);
void gb_audio_manager_remove_all(void)
{
struct gb_audio_manager_module *module, *next;
- int is_empty = 1;
+ int is_empty;
down_write(&modules_rwsem);
diff --git a/drivers/staging/greybus/authentication.c b/drivers/staging/greybus/authentication.c
index a5d7c53df987..297e69f011c7 100644
--- a/drivers/staging/greybus/authentication.c
+++ b/drivers/staging/greybus/authentication.c
@@ -6,8 +6,7 @@
* Copyright 2016 Linaro Ltd.
*/
-#include "greybus.h"
-
+#include <linux/greybus.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
diff --git a/drivers/staging/greybus/bootrom.c b/drivers/staging/greybus/bootrom.c
index 402e6360834f..a8efb86de140 100644
--- a/drivers/staging/greybus/bootrom.c
+++ b/drivers/staging/greybus/bootrom.c
@@ -10,8 +10,8 @@
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "firmware.h"
/* Timeout, in jiffies, within which the next request must be received */
diff --git a/drivers/staging/greybus/bundle.c b/drivers/staging/greybus/bundle.c
deleted file mode 100644
index 3f702db9e098..000000000000
--- a/drivers/staging/greybus/bundle.c
+++ /dev/null
@@ -1,252 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus bundles
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- */
-
-#include "greybus.h"
-#include "greybus_trace.h"
-
-static ssize_t bundle_class_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_bundle *bundle = to_gb_bundle(dev);
-
- return sprintf(buf, "0x%02x\n", bundle->class);
-}
-static DEVICE_ATTR_RO(bundle_class);
-
-static ssize_t bundle_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_bundle *bundle = to_gb_bundle(dev);
-
- return sprintf(buf, "%u\n", bundle->id);
-}
-static DEVICE_ATTR_RO(bundle_id);
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct gb_bundle *bundle = to_gb_bundle(dev);
-
- if (!bundle->state)
- return sprintf(buf, "\n");
-
- return sprintf(buf, "%s\n", bundle->state);
-}
-
-static ssize_t state_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct gb_bundle *bundle = to_gb_bundle(dev);
-
- kfree(bundle->state);
- bundle->state = kstrdup(buf, GFP_KERNEL);
- if (!bundle->state)
- return -ENOMEM;
-
- /* Tell userspace that the file contents changed */
- sysfs_notify(&bundle->dev.kobj, NULL, "state");
-
- return size;
-}
-static DEVICE_ATTR_RW(state);
-
-static struct attribute *bundle_attrs[] = {
- &dev_attr_bundle_class.attr,
- &dev_attr_bundle_id.attr,
- &dev_attr_state.attr,
- NULL,
-};
-
-ATTRIBUTE_GROUPS(bundle);
-
-static struct gb_bundle *gb_bundle_find(struct gb_interface *intf,
- u8 bundle_id)
-{
- struct gb_bundle *bundle;
-
- list_for_each_entry(bundle, &intf->bundles, links) {
- if (bundle->id == bundle_id)
- return bundle;
- }
-
- return NULL;
-}
-
-static void gb_bundle_release(struct device *dev)
-{
- struct gb_bundle *bundle = to_gb_bundle(dev);
-
- trace_gb_bundle_release(bundle);
-
- kfree(bundle->state);
- kfree(bundle->cport_desc);
- kfree(bundle);
-}
-
-#ifdef CONFIG_PM
-static void gb_bundle_disable_all_connections(struct gb_bundle *bundle)
-{
- struct gb_connection *connection;
-
- list_for_each_entry(connection, &bundle->connections, bundle_links)
- gb_connection_disable(connection);
-}
-
-static void gb_bundle_enable_all_connections(struct gb_bundle *bundle)
-{
- struct gb_connection *connection;
-
- list_for_each_entry(connection, &bundle->connections, bundle_links)
- gb_connection_enable(connection);
-}
-
-static int gb_bundle_suspend(struct device *dev)
-{
- struct gb_bundle *bundle = to_gb_bundle(dev);
- const struct dev_pm_ops *pm = dev->driver->pm;
- int ret;
-
- if (pm && pm->runtime_suspend) {
- ret = pm->runtime_suspend(&bundle->dev);
- if (ret)
- return ret;
- } else {
- gb_bundle_disable_all_connections(bundle);
- }
-
- ret = gb_control_bundle_suspend(bundle->intf->control, bundle->id);
- if (ret) {
- if (pm && pm->runtime_resume)
- ret = pm->runtime_resume(dev);
- else
- gb_bundle_enable_all_connections(bundle);
-
- return ret;
- }
-
- return 0;
-}
-
-static int gb_bundle_resume(struct device *dev)
-{
- struct gb_bundle *bundle = to_gb_bundle(dev);
- const struct dev_pm_ops *pm = dev->driver->pm;
- int ret;
-
- ret = gb_control_bundle_resume(bundle->intf->control, bundle->id);
- if (ret)
- return ret;
-
- if (pm && pm->runtime_resume) {
- ret = pm->runtime_resume(dev);
- if (ret)
- return ret;
- } else {
- gb_bundle_enable_all_connections(bundle);
- }
-
- return 0;
-}
-
-static int gb_bundle_idle(struct device *dev)
-{
- pm_runtime_mark_last_busy(dev);
- pm_request_autosuspend(dev);
-
- return 0;
-}
-#endif
-
-static const struct dev_pm_ops gb_bundle_pm_ops = {
- SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle)
-};
-
-struct device_type greybus_bundle_type = {
- .name = "greybus_bundle",
- .release = gb_bundle_release,
- .pm = &gb_bundle_pm_ops,
-};
-
-/*
- * Create a gb_bundle structure to represent a discovered
- * bundle. Returns a pointer to the new bundle or a null
- * pointer if a failure occurs due to memory exhaustion.
- */
-struct gb_bundle *gb_bundle_create(struct gb_interface *intf, u8 bundle_id,
- u8 class)
-{
- struct gb_bundle *bundle;
-
- if (bundle_id == BUNDLE_ID_NONE) {
- dev_err(&intf->dev, "can't use bundle id %u\n", bundle_id);
- return NULL;
- }
-
- /*
- * Reject any attempt to reuse a bundle id. We initialize
- * these serially, so there's no need to worry about keeping
- * the interface bundle list locked here.
- */
- if (gb_bundle_find(intf, bundle_id)) {
- dev_err(&intf->dev, "duplicate bundle id %u\n", bundle_id);
- return NULL;
- }
-
- bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
- if (!bundle)
- return NULL;
-
- bundle->intf = intf;
- bundle->id = bundle_id;
- bundle->class = class;
- INIT_LIST_HEAD(&bundle->connections);
-
- bundle->dev.parent = &intf->dev;
- bundle->dev.bus = &greybus_bus_type;
- bundle->dev.type = &greybus_bundle_type;
- bundle->dev.groups = bundle_groups;
- bundle->dev.dma_mask = intf->dev.dma_mask;
- device_initialize(&bundle->dev);
- dev_set_name(&bundle->dev, "%s.%d", dev_name(&intf->dev), bundle_id);
-
- list_add(&bundle->links, &intf->bundles);
-
- trace_gb_bundle_create(bundle);
-
- return bundle;
-}
-
-int gb_bundle_add(struct gb_bundle *bundle)
-{
- int ret;
-
- ret = device_add(&bundle->dev);
- if (ret) {
- dev_err(&bundle->dev, "failed to register bundle: %d\n", ret);
- return ret;
- }
-
- trace_gb_bundle_add(bundle);
-
- return 0;
-}
-
-/*
- * Tear down a previously set up bundle.
- */
-void gb_bundle_destroy(struct gb_bundle *bundle)
-{
- trace_gb_bundle_destroy(bundle);
-
- if (device_is_registered(&bundle->dev))
- device_del(&bundle->dev);
-
- list_del(&bundle->links);
-
- put_device(&bundle->dev);
-}
diff --git a/drivers/staging/greybus/bundle.h b/drivers/staging/greybus/bundle.h
deleted file mode 100644
index 8734d2055657..000000000000
--- a/drivers/staging/greybus/bundle.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Greybus bundles
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- */
-
-#ifndef __BUNDLE_H
-#define __BUNDLE_H
-
-#include <linux/list.h>
-
-#define BUNDLE_ID_NONE U8_MAX
-
-/* Greybus "public" definitions" */
-struct gb_bundle {
- struct device dev;
- struct gb_interface *intf;
-
- u8 id;
- u8 class;
- u8 class_major;
- u8 class_minor;
-
- size_t num_cports;
- struct greybus_descriptor_cport *cport_desc;
-
- struct list_head connections;
- u8 *state;
-
- struct list_head links; /* interface->bundles */
-};
-#define to_gb_bundle(d) container_of(d, struct gb_bundle, dev)
-
-/* Greybus "private" definitions" */
-struct gb_bundle *gb_bundle_create(struct gb_interface *intf, u8 bundle_id,
- u8 class);
-int gb_bundle_add(struct gb_bundle *bundle);
-void gb_bundle_destroy(struct gb_bundle *bundle);
-
-/* Bundle Runtime PM wrappers */
-#ifdef CONFIG_PM
-static inline int gb_pm_runtime_get_sync(struct gb_bundle *bundle)
-{
- int retval;
-
- retval = pm_runtime_get_sync(&bundle->dev);
- if (retval < 0) {
- dev_err(&bundle->dev,
- "pm_runtime_get_sync failed: %d\n", retval);
- pm_runtime_put_noidle(&bundle->dev);
- return retval;
- }
-
- return 0;
-}
-
-static inline int gb_pm_runtime_put_autosuspend(struct gb_bundle *bundle)
-{
- int retval;
-
- pm_runtime_mark_last_busy(&bundle->dev);
- retval = pm_runtime_put_autosuspend(&bundle->dev);
-
- return retval;
-}
-
-static inline void gb_pm_runtime_get_noresume(struct gb_bundle *bundle)
-{
- pm_runtime_get_noresume(&bundle->dev);
-}
-
-static inline void gb_pm_runtime_put_noidle(struct gb_bundle *bundle)
-{
- pm_runtime_put_noidle(&bundle->dev);
-}
-
-#else
-static inline int gb_pm_runtime_get_sync(struct gb_bundle *bundle)
-{ return 0; }
-static inline int gb_pm_runtime_put_autosuspend(struct gb_bundle *bundle)
-{ return 0; }
-
-static inline void gb_pm_runtime_get_noresume(struct gb_bundle *bundle) {}
-static inline void gb_pm_runtime_put_noidle(struct gb_bundle *bundle) {}
-#endif
-
-#endif /* __BUNDLE_H */
diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c
index 615c8e7fd51e..b570e13394ac 100644
--- a/drivers/staging/greybus/camera.c
+++ b/drivers/staging/greybus/camera.c
@@ -14,9 +14,9 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
+#include <linux/greybus.h>
#include "gb-camera.h"
-#include "greybus.h"
#include "greybus_protocols.h"
enum gb_camera_debugs_buffer_id {
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
deleted file mode 100644
index eda964208cce..000000000000
--- a/drivers/staging/greybus/connection.c
+++ /dev/null
@@ -1,942 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus connections
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- */
-
-#include <linux/workqueue.h>
-
-#include "greybus.h"
-#include "greybus_trace.h"
-
-#define GB_CONNECTION_CPORT_QUIESCE_TIMEOUT 1000
-
-static void gb_connection_kref_release(struct kref *kref);
-
-static DEFINE_SPINLOCK(gb_connections_lock);
-static DEFINE_MUTEX(gb_connection_mutex);
-
-/* Caller holds gb_connection_mutex. */
-static bool gb_connection_cport_in_use(struct gb_interface *intf, u16 cport_id)
-{
- struct gb_host_device *hd = intf->hd;
- struct gb_connection *connection;
-
- list_for_each_entry(connection, &hd->connections, hd_links) {
- if (connection->intf == intf &&
- connection->intf_cport_id == cport_id)
- return true;
- }
-
- return false;
-}
-
-static void gb_connection_get(struct gb_connection *connection)
-{
- kref_get(&connection->kref);
-
- trace_gb_connection_get(connection);
-}
-
-static void gb_connection_put(struct gb_connection *connection)
-{
- trace_gb_connection_put(connection);
-
- kref_put(&connection->kref, gb_connection_kref_release);
-}
-
-/*
- * Returns a reference-counted pointer to the connection if found.
- */
-static struct gb_connection *
-gb_connection_hd_find(struct gb_host_device *hd, u16 cport_id)
-{
- struct gb_connection *connection;
- unsigned long flags;
-
- spin_lock_irqsave(&gb_connections_lock, flags);
- list_for_each_entry(connection, &hd->connections, hd_links)
- if (connection->hd_cport_id == cport_id) {
- gb_connection_get(connection);
- goto found;
- }
- connection = NULL;
-found:
- spin_unlock_irqrestore(&gb_connections_lock, flags);
-
- return connection;
-}
-
-/*
- * Callback from the host driver to let us know that data has been
- * received on the bundle.
- */
-void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id,
- u8 *data, size_t length)
-{
- struct gb_connection *connection;
-
- trace_gb_hd_in(hd);
-
- connection = gb_connection_hd_find(hd, cport_id);
- if (!connection) {
- dev_err(&hd->dev,
- "nonexistent connection (%zu bytes dropped)\n", length);
- return;
- }
- gb_connection_recv(connection, data, length);
- gb_connection_put(connection);
-}
-EXPORT_SYMBOL_GPL(greybus_data_rcvd);
-
-static void gb_connection_kref_release(struct kref *kref)
-{
- struct gb_connection *connection;
-
- connection = container_of(kref, struct gb_connection, kref);
-
- trace_gb_connection_release(connection);
-
- kfree(connection);
-}
-
-static void gb_connection_init_name(struct gb_connection *connection)
-{
- u16 hd_cport_id = connection->hd_cport_id;
- u16 cport_id = 0;
- u8 intf_id = 0;
-
- if (connection->intf) {
- intf_id = connection->intf->interface_id;
- cport_id = connection->intf_cport_id;
- }
-
- snprintf(connection->name, sizeof(connection->name),
- "%u/%u:%u", hd_cport_id, intf_id, cport_id);
-}
-
-/*
- * _gb_connection_create() - create a Greybus connection
- * @hd: host device of the connection
- * @hd_cport_id: host-device cport id, or -1 for dynamic allocation
- * @intf: remote interface, or NULL for static connections
- * @bundle: remote-interface bundle (may be NULL)
- * @cport_id: remote-interface cport id, or 0 for static connections
- * @handler: request handler (may be NULL)
- * @flags: connection flags
- *
- * Create a Greybus connection, representing the bidirectional link
- * between a CPort on a (local) Greybus host device and a CPort on
- * another Greybus interface.
- *
- * A connection also maintains the state of operations sent over the
- * connection.
- *
- * Serialised against concurrent create and destroy using the
- * gb_connection_mutex.
- *
- * Return: A pointer to the new connection if successful, or an ERR_PTR
- * otherwise.
- */
-static struct gb_connection *
-_gb_connection_create(struct gb_host_device *hd, int hd_cport_id,
- struct gb_interface *intf,
- struct gb_bundle *bundle, int cport_id,
- gb_request_handler_t handler,
- unsigned long flags)
-{
- struct gb_connection *connection;
- int ret;
-
- mutex_lock(&gb_connection_mutex);
-
- if (intf && gb_connection_cport_in_use(intf, cport_id)) {
- dev_err(&intf->dev, "cport %u already in use\n", cport_id);
- ret = -EBUSY;
- goto err_unlock;
- }
-
- ret = gb_hd_cport_allocate(hd, hd_cport_id, flags);
- if (ret < 0) {
- dev_err(&hd->dev, "failed to allocate cport: %d\n", ret);
- goto err_unlock;
- }
- hd_cport_id = ret;
-
- connection = kzalloc(sizeof(*connection), GFP_KERNEL);
- if (!connection) {
- ret = -ENOMEM;
- goto err_hd_cport_release;
- }
-
- connection->hd_cport_id = hd_cport_id;
- connection->intf_cport_id = cport_id;
- connection->hd = hd;
- connection->intf = intf;
- connection->bundle = bundle;
- connection->handler = handler;
- connection->flags = flags;
- if (intf && (intf->quirks & GB_INTERFACE_QUIRK_NO_CPORT_FEATURES))
- connection->flags |= GB_CONNECTION_FLAG_NO_FLOWCTRL;
- connection->state = GB_CONNECTION_STATE_DISABLED;
-
- atomic_set(&connection->op_cycle, 0);
- mutex_init(&connection->mutex);
- spin_lock_init(&connection->lock);
- INIT_LIST_HEAD(&connection->operations);
-
- connection->wq = alloc_workqueue("%s:%d", WQ_UNBOUND, 1,
- dev_name(&hd->dev), hd_cport_id);
- if (!connection->wq) {
- ret = -ENOMEM;
- goto err_free_connection;
- }
-
- kref_init(&connection->kref);
-
- gb_connection_init_name(connection);
-
- spin_lock_irq(&gb_connections_lock);
- list_add(&connection->hd_links, &hd->connections);
-
- if (bundle)
- list_add(&connection->bundle_links, &bundle->connections);
- else
- INIT_LIST_HEAD(&connection->bundle_links);
-
- spin_unlock_irq(&gb_connections_lock);
-
- mutex_unlock(&gb_connection_mutex);
-
- trace_gb_connection_create(connection);
-
- return connection;
-
-err_free_connection:
- kfree(connection);
-err_hd_cport_release:
- gb_hd_cport_release(hd, hd_cport_id);
-err_unlock:
- mutex_unlock(&gb_connection_mutex);
-
- return ERR_PTR(ret);
-}
-
-struct gb_connection *
-gb_connection_create_static(struct gb_host_device *hd, u16 hd_cport_id,
- gb_request_handler_t handler)
-{
- return _gb_connection_create(hd, hd_cport_id, NULL, NULL, 0, handler,
- GB_CONNECTION_FLAG_HIGH_PRIO);
-}
-
-struct gb_connection *
-gb_connection_create_control(struct gb_interface *intf)
-{
- return _gb_connection_create(intf->hd, -1, intf, NULL, 0, NULL,
- GB_CONNECTION_FLAG_CONTROL |
- GB_CONNECTION_FLAG_HIGH_PRIO);
-}
-
-struct gb_connection *
-gb_connection_create(struct gb_bundle *bundle, u16 cport_id,
- gb_request_handler_t handler)
-{
- struct gb_interface *intf = bundle->intf;
-
- return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id,
- handler, 0);
-}
-EXPORT_SYMBOL_GPL(gb_connection_create);
-
-struct gb_connection *
-gb_connection_create_flags(struct gb_bundle *bundle, u16 cport_id,
- gb_request_handler_t handler,
- unsigned long flags)
-{
- struct gb_interface *intf = bundle->intf;
-
- if (WARN_ON_ONCE(flags & GB_CONNECTION_FLAG_CORE_MASK))
- flags &= ~GB_CONNECTION_FLAG_CORE_MASK;
-
- return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id,
- handler, flags);
-}
-EXPORT_SYMBOL_GPL(gb_connection_create_flags);
-
-struct gb_connection *
-gb_connection_create_offloaded(struct gb_bundle *bundle, u16 cport_id,
- unsigned long flags)
-{
- flags |= GB_CONNECTION_FLAG_OFFLOADED;
-
- return gb_connection_create_flags(bundle, cport_id, NULL, flags);
-}
-EXPORT_SYMBOL_GPL(gb_connection_create_offloaded);
-
-static int gb_connection_hd_cport_enable(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- int ret;
-
- if (!hd->driver->cport_enable)
- return 0;
-
- ret = hd->driver->cport_enable(hd, connection->hd_cport_id,
- connection->flags);
- if (ret) {
- dev_err(&hd->dev, "%s: failed to enable host cport: %d\n",
- connection->name, ret);
- return ret;
- }
-
- return 0;
-}
-
-static void gb_connection_hd_cport_disable(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- int ret;
-
- if (!hd->driver->cport_disable)
- return;
-
- ret = hd->driver->cport_disable(hd, connection->hd_cport_id);
- if (ret) {
- dev_err(&hd->dev, "%s: failed to disable host cport: %d\n",
- connection->name, ret);
- }
-}
-
-static int gb_connection_hd_cport_connected(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- int ret;
-
- if (!hd->driver->cport_connected)
- return 0;
-
- ret = hd->driver->cport_connected(hd, connection->hd_cport_id);
- if (ret) {
- dev_err(&hd->dev, "%s: failed to set connected state: %d\n",
- connection->name, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int gb_connection_hd_cport_flush(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- int ret;
-
- if (!hd->driver->cport_flush)
- return 0;
-
- ret = hd->driver->cport_flush(hd, connection->hd_cport_id);
- if (ret) {
- dev_err(&hd->dev, "%s: failed to flush host cport: %d\n",
- connection->name, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int gb_connection_hd_cport_quiesce(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- size_t peer_space;
- int ret;
-
- if (!hd->driver->cport_quiesce)
- return 0;
-
- peer_space = sizeof(struct gb_operation_msg_hdr) +
- sizeof(struct gb_cport_shutdown_request);
-
- if (connection->mode_switch)
- peer_space += sizeof(struct gb_operation_msg_hdr);
-
- if (!hd->driver->cport_quiesce)
- return 0;
-
- ret = hd->driver->cport_quiesce(hd, connection->hd_cport_id,
- peer_space,
- GB_CONNECTION_CPORT_QUIESCE_TIMEOUT);
- if (ret) {
- dev_err(&hd->dev, "%s: failed to quiesce host cport: %d\n",
- connection->name, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int gb_connection_hd_cport_clear(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- int ret;
-
- if (!hd->driver->cport_clear)
- return 0;
-
- ret = hd->driver->cport_clear(hd, connection->hd_cport_id);
- if (ret) {
- dev_err(&hd->dev, "%s: failed to clear host cport: %d\n",
- connection->name, ret);
- return ret;
- }
-
- return 0;
-}
-
-/*
- * Request the SVC to create a connection from AP's cport to interface's
- * cport.
- */
-static int
-gb_connection_svc_connection_create(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- struct gb_interface *intf;
- u8 cport_flags;
- int ret;
-
- if (gb_connection_is_static(connection))
- return 0;
-
- intf = connection->intf;
-
- /*
- * Enable either E2EFC or CSD, unless no flow control is requested.
- */
- cport_flags = GB_SVC_CPORT_FLAG_CSV_N;
- if (gb_connection_flow_control_disabled(connection)) {
- cport_flags |= GB_SVC_CPORT_FLAG_CSD_N;
- } else if (gb_connection_e2efc_enabled(connection)) {
- cport_flags |= GB_SVC_CPORT_FLAG_CSD_N |
- GB_SVC_CPORT_FLAG_E2EFC;
- }
-
- ret = gb_svc_connection_create(hd->svc,
- hd->svc->ap_intf_id,
- connection->hd_cport_id,
- intf->interface_id,
- connection->intf_cport_id,
- cport_flags);
- if (ret) {
- dev_err(&connection->hd->dev,
- "%s: failed to create svc connection: %d\n",
- connection->name, ret);
- return ret;
- }
-
- return 0;
-}
-
-static void
-gb_connection_svc_connection_destroy(struct gb_connection *connection)
-{
- if (gb_connection_is_static(connection))
- return;
-
- gb_svc_connection_destroy(connection->hd->svc,
- connection->hd->svc->ap_intf_id,
- connection->hd_cport_id,
- connection->intf->interface_id,
- connection->intf_cport_id);
-}
-
-/* Inform Interface about active CPorts */
-static int gb_connection_control_connected(struct gb_connection *connection)
-{
- struct gb_control *control;
- u16 cport_id = connection->intf_cport_id;
- int ret;
-
- if (gb_connection_is_static(connection))
- return 0;
-
- if (gb_connection_is_control(connection))
- return 0;
-
- control = connection->intf->control;
-
- ret = gb_control_connected_operation(control, cport_id);
- if (ret) {
- dev_err(&connection->bundle->dev,
- "failed to connect cport: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static void
-gb_connection_control_disconnecting(struct gb_connection *connection)
-{
- struct gb_control *control;
- u16 cport_id = connection->intf_cport_id;
- int ret;
-
- if (gb_connection_is_static(connection))
- return;
-
- control = connection->intf->control;
-
- ret = gb_control_disconnecting_operation(control, cport_id);
- if (ret) {
- dev_err(&connection->hd->dev,
- "%s: failed to send disconnecting: %d\n",
- connection->name, ret);
- }
-}
-
-static void
-gb_connection_control_disconnected(struct gb_connection *connection)
-{
- struct gb_control *control;
- u16 cport_id = connection->intf_cport_id;
- int ret;
-
- if (gb_connection_is_static(connection))
- return;
-
- control = connection->intf->control;
-
- if (gb_connection_is_control(connection)) {
- if (connection->mode_switch) {
- ret = gb_control_mode_switch_operation(control);
- if (ret) {
- /*
- * Allow mode switch to time out waiting for
- * mailbox event.
- */
- return;
- }
- }
-
- return;
- }
-
- ret = gb_control_disconnected_operation(control, cport_id);
- if (ret) {
- dev_warn(&connection->bundle->dev,
- "failed to disconnect cport: %d\n", ret);
- }
-}
-
-static int gb_connection_shutdown_operation(struct gb_connection *connection,
- u8 phase)
-{
- struct gb_cport_shutdown_request *req;
- struct gb_operation *operation;
- int ret;
-
- operation = gb_operation_create_core(connection,
- GB_REQUEST_TYPE_CPORT_SHUTDOWN,
- sizeof(*req), 0, 0,
- GFP_KERNEL);
- if (!operation)
- return -ENOMEM;
-
- req = operation->request->payload;
- req->phase = phase;
-
- ret = gb_operation_request_send_sync(operation);
-
- gb_operation_put(operation);
-
- return ret;
-}
-
-static int gb_connection_cport_shutdown(struct gb_connection *connection,
- u8 phase)
-{
- struct gb_host_device *hd = connection->hd;
- const struct gb_hd_driver *drv = hd->driver;
- int ret;
-
- if (gb_connection_is_static(connection))
- return 0;
-
- if (gb_connection_is_offloaded(connection)) {
- if (!drv->cport_shutdown)
- return 0;
-
- ret = drv->cport_shutdown(hd, connection->hd_cport_id, phase,
- GB_OPERATION_TIMEOUT_DEFAULT);
- } else {
- ret = gb_connection_shutdown_operation(connection, phase);
- }
-
- if (ret) {
- dev_err(&hd->dev, "%s: failed to send cport shutdown (phase %d): %d\n",
- connection->name, phase, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int
-gb_connection_cport_shutdown_phase_1(struct gb_connection *connection)
-{
- return gb_connection_cport_shutdown(connection, 1);
-}
-
-static int
-gb_connection_cport_shutdown_phase_2(struct gb_connection *connection)
-{
- return gb_connection_cport_shutdown(connection, 2);
-}
-
-/*
- * Cancel all active operations on a connection.
- *
- * Locking: Called with connection lock held and state set to DISABLED or
- * DISCONNECTING.
- */
-static void gb_connection_cancel_operations(struct gb_connection *connection,
- int errno)
- __must_hold(&connection->lock)
-{
- struct gb_operation *operation;
-
- while (!list_empty(&connection->operations)) {
- operation = list_last_entry(&connection->operations,
- struct gb_operation, links);
- gb_operation_get(operation);
- spin_unlock_irq(&connection->lock);
-
- if (gb_operation_is_incoming(operation))
- gb_operation_cancel_incoming(operation, errno);
- else
- gb_operation_cancel(operation, errno);
-
- gb_operation_put(operation);
-
- spin_lock_irq(&connection->lock);
- }
-}
-
-/*
- * Cancel all active incoming operations on a connection.
- *
- * Locking: Called with connection lock held and state set to ENABLED_TX.
- */
-static void
-gb_connection_flush_incoming_operations(struct gb_connection *connection,
- int errno)
- __must_hold(&connection->lock)
-{
- struct gb_operation *operation;
- bool incoming;
-
- while (!list_empty(&connection->operations)) {
- incoming = false;
- list_for_each_entry(operation, &connection->operations,
- links) {
- if (gb_operation_is_incoming(operation)) {
- gb_operation_get(operation);
- incoming = true;
- break;
- }
- }
-
- if (!incoming)
- break;
-
- spin_unlock_irq(&connection->lock);
-
- /* FIXME: flush, not cancel? */
- gb_operation_cancel_incoming(operation, errno);
- gb_operation_put(operation);
-
- spin_lock_irq(&connection->lock);
- }
-}
-
-/*
- * _gb_connection_enable() - enable a connection
- * @connection: connection to enable
- * @rx: whether to enable incoming requests
- *
- * Connection-enable helper for DISABLED->ENABLED, DISABLED->ENABLED_TX, and
- * ENABLED_TX->ENABLED state transitions.
- *
- * Locking: Caller holds connection->mutex.
- */
-static int _gb_connection_enable(struct gb_connection *connection, bool rx)
-{
- int ret;
-
- /* Handle ENABLED_TX -> ENABLED transitions. */
- if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) {
- if (!(connection->handler && rx))
- return 0;
-
- spin_lock_irq(&connection->lock);
- connection->state = GB_CONNECTION_STATE_ENABLED;
- spin_unlock_irq(&connection->lock);
-
- return 0;
- }
-
- ret = gb_connection_hd_cport_enable(connection);
- if (ret)
- return ret;
-
- ret = gb_connection_svc_connection_create(connection);
- if (ret)
- goto err_hd_cport_clear;
-
- ret = gb_connection_hd_cport_connected(connection);
- if (ret)
- goto err_svc_connection_destroy;
-
- spin_lock_irq(&connection->lock);
- if (connection->handler && rx)
- connection->state = GB_CONNECTION_STATE_ENABLED;
- else
- connection->state = GB_CONNECTION_STATE_ENABLED_TX;
- spin_unlock_irq(&connection->lock);
-
- ret = gb_connection_control_connected(connection);
- if (ret)
- goto err_control_disconnecting;
-
- return 0;
-
-err_control_disconnecting:
- spin_lock_irq(&connection->lock);
- connection->state = GB_CONNECTION_STATE_DISCONNECTING;
- gb_connection_cancel_operations(connection, -ESHUTDOWN);
- spin_unlock_irq(&connection->lock);
-
- /* Transmit queue should already be empty. */
- gb_connection_hd_cport_flush(connection);
-
- gb_connection_control_disconnecting(connection);
- gb_connection_cport_shutdown_phase_1(connection);
- gb_connection_hd_cport_quiesce(connection);
- gb_connection_cport_shutdown_phase_2(connection);
- gb_connection_control_disconnected(connection);
- connection->state = GB_CONNECTION_STATE_DISABLED;
-err_svc_connection_destroy:
- gb_connection_svc_connection_destroy(connection);
-err_hd_cport_clear:
- gb_connection_hd_cport_clear(connection);
-
- gb_connection_hd_cport_disable(connection);
-
- return ret;
-}
-
-int gb_connection_enable(struct gb_connection *connection)
-{
- int ret = 0;
-
- mutex_lock(&connection->mutex);
-
- if (connection->state == GB_CONNECTION_STATE_ENABLED)
- goto out_unlock;
-
- ret = _gb_connection_enable(connection, true);
- if (!ret)
- trace_gb_connection_enable(connection);
-
-out_unlock:
- mutex_unlock(&connection->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_connection_enable);
-
-int gb_connection_enable_tx(struct gb_connection *connection)
-{
- int ret = 0;
-
- mutex_lock(&connection->mutex);
-
- if (connection->state == GB_CONNECTION_STATE_ENABLED) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- if (connection->state == GB_CONNECTION_STATE_ENABLED_TX)
- goto out_unlock;
-
- ret = _gb_connection_enable(connection, false);
- if (!ret)
- trace_gb_connection_enable(connection);
-
-out_unlock:
- mutex_unlock(&connection->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_connection_enable_tx);
-
-void gb_connection_disable_rx(struct gb_connection *connection)
-{
- mutex_lock(&connection->mutex);
-
- spin_lock_irq(&connection->lock);
- if (connection->state != GB_CONNECTION_STATE_ENABLED) {
- spin_unlock_irq(&connection->lock);
- goto out_unlock;
- }
- connection->state = GB_CONNECTION_STATE_ENABLED_TX;
- gb_connection_flush_incoming_operations(connection, -ESHUTDOWN);
- spin_unlock_irq(&connection->lock);
-
- trace_gb_connection_disable(connection);
-
-out_unlock:
- mutex_unlock(&connection->mutex);
-}
-EXPORT_SYMBOL_GPL(gb_connection_disable_rx);
-
-void gb_connection_mode_switch_prepare(struct gb_connection *connection)
-{
- connection->mode_switch = true;
-}
-
-void gb_connection_mode_switch_complete(struct gb_connection *connection)
-{
- gb_connection_svc_connection_destroy(connection);
- gb_connection_hd_cport_clear(connection);
-
- gb_connection_hd_cport_disable(connection);
-
- connection->mode_switch = false;
-}
-
-void gb_connection_disable(struct gb_connection *connection)
-{
- mutex_lock(&connection->mutex);
-
- if (connection->state == GB_CONNECTION_STATE_DISABLED)
- goto out_unlock;
-
- trace_gb_connection_disable(connection);
-
- spin_lock_irq(&connection->lock);
- connection->state = GB_CONNECTION_STATE_DISCONNECTING;
- gb_connection_cancel_operations(connection, -ESHUTDOWN);
- spin_unlock_irq(&connection->lock);
-
- gb_connection_hd_cport_flush(connection);
-
- gb_connection_control_disconnecting(connection);
- gb_connection_cport_shutdown_phase_1(connection);
- gb_connection_hd_cport_quiesce(connection);
- gb_connection_cport_shutdown_phase_2(connection);
- gb_connection_control_disconnected(connection);
-
- connection->state = GB_CONNECTION_STATE_DISABLED;
-
- /* control-connection tear down is deferred when mode switching */
- if (!connection->mode_switch) {
- gb_connection_svc_connection_destroy(connection);
- gb_connection_hd_cport_clear(connection);
-
- gb_connection_hd_cport_disable(connection);
- }
-
-out_unlock:
- mutex_unlock(&connection->mutex);
-}
-EXPORT_SYMBOL_GPL(gb_connection_disable);
-
-/* Disable a connection without communicating with the remote end. */
-void gb_connection_disable_forced(struct gb_connection *connection)
-{
- mutex_lock(&connection->mutex);
-
- if (connection->state == GB_CONNECTION_STATE_DISABLED)
- goto out_unlock;
-
- trace_gb_connection_disable(connection);
-
- spin_lock_irq(&connection->lock);
- connection->state = GB_CONNECTION_STATE_DISABLED;
- gb_connection_cancel_operations(connection, -ESHUTDOWN);
- spin_unlock_irq(&connection->lock);
-
- gb_connection_hd_cport_flush(connection);
-
- gb_connection_svc_connection_destroy(connection);
- gb_connection_hd_cport_clear(connection);
-
- gb_connection_hd_cport_disable(connection);
-out_unlock:
- mutex_unlock(&connection->mutex);
-}
-EXPORT_SYMBOL_GPL(gb_connection_disable_forced);
-
-/* Caller must have disabled the connection before destroying it. */
-void gb_connection_destroy(struct gb_connection *connection)
-{
- if (!connection)
- return;
-
- if (WARN_ON(connection->state != GB_CONNECTION_STATE_DISABLED))
- gb_connection_disable(connection);
-
- mutex_lock(&gb_connection_mutex);
-
- spin_lock_irq(&gb_connections_lock);
- list_del(&connection->bundle_links);
- list_del(&connection->hd_links);
- spin_unlock_irq(&gb_connections_lock);
-
- destroy_workqueue(connection->wq);
-
- gb_hd_cport_release(connection->hd, connection->hd_cport_id);
- connection->hd_cport_id = CPORT_ID_BAD;
-
- mutex_unlock(&gb_connection_mutex);
-
- gb_connection_put(connection);
-}
-EXPORT_SYMBOL_GPL(gb_connection_destroy);
-
-void gb_connection_latency_tag_enable(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- int ret;
-
- if (!hd->driver->latency_tag_enable)
- return;
-
- ret = hd->driver->latency_tag_enable(hd, connection->hd_cport_id);
- if (ret) {
- dev_err(&connection->hd->dev,
- "%s: failed to enable latency tag: %d\n",
- connection->name, ret);
- }
-}
-EXPORT_SYMBOL_GPL(gb_connection_latency_tag_enable);
-
-void gb_connection_latency_tag_disable(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
- int ret;
-
- if (!hd->driver->latency_tag_disable)
- return;
-
- ret = hd->driver->latency_tag_disable(hd, connection->hd_cport_id);
- if (ret) {
- dev_err(&connection->hd->dev,
- "%s: failed to disable latency tag: %d\n",
- connection->name, ret);
- }
-}
-EXPORT_SYMBOL_GPL(gb_connection_latency_tag_disable);
diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h
deleted file mode 100644
index 5ca3befc0636..000000000000
--- a/drivers/staging/greybus/connection.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Greybus connections
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- */
-
-#ifndef __CONNECTION_H
-#define __CONNECTION_H
-
-#include <linux/list.h>
-#include <linux/kfifo.h>
-
-#define GB_CONNECTION_FLAG_CSD BIT(0)
-#define GB_CONNECTION_FLAG_NO_FLOWCTRL BIT(1)
-#define GB_CONNECTION_FLAG_OFFLOADED BIT(2)
-#define GB_CONNECTION_FLAG_CDSI1 BIT(3)
-#define GB_CONNECTION_FLAG_CONTROL BIT(4)
-#define GB_CONNECTION_FLAG_HIGH_PRIO BIT(5)
-
-#define GB_CONNECTION_FLAG_CORE_MASK GB_CONNECTION_FLAG_CONTROL
-
-enum gb_connection_state {
- GB_CONNECTION_STATE_DISABLED = 0,
- GB_CONNECTION_STATE_ENABLED_TX = 1,
- GB_CONNECTION_STATE_ENABLED = 2,
- GB_CONNECTION_STATE_DISCONNECTING = 3,
-};
-
-struct gb_operation;
-
-typedef int (*gb_request_handler_t)(struct gb_operation *);
-
-struct gb_connection {
- struct gb_host_device *hd;
- struct gb_interface *intf;
- struct gb_bundle *bundle;
- struct kref kref;
- u16 hd_cport_id;
- u16 intf_cport_id;
-
- struct list_head hd_links;
- struct list_head bundle_links;
-
- gb_request_handler_t handler;
- unsigned long flags;
-
- struct mutex mutex;
- spinlock_t lock;
- enum gb_connection_state state;
- struct list_head operations;
-
- char name[16];
- struct workqueue_struct *wq;
-
- atomic_t op_cycle;
-
- void *private;
-
- bool mode_switch;
-};
-
-struct gb_connection *gb_connection_create_static(struct gb_host_device *hd,
- u16 hd_cport_id, gb_request_handler_t handler);
-struct gb_connection *gb_connection_create_control(struct gb_interface *intf);
-struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
- u16 cport_id, gb_request_handler_t handler);
-struct gb_connection *gb_connection_create_flags(struct gb_bundle *bundle,
- u16 cport_id, gb_request_handler_t handler,
- unsigned long flags);
-struct gb_connection *gb_connection_create_offloaded(struct gb_bundle *bundle,
- u16 cport_id, unsigned long flags);
-void gb_connection_destroy(struct gb_connection *connection);
-
-static inline bool gb_connection_is_static(struct gb_connection *connection)
-{
- return !connection->intf;
-}
-
-int gb_connection_enable(struct gb_connection *connection);
-int gb_connection_enable_tx(struct gb_connection *connection);
-void gb_connection_disable_rx(struct gb_connection *connection);
-void gb_connection_disable(struct gb_connection *connection);
-void gb_connection_disable_forced(struct gb_connection *connection);
-
-void gb_connection_mode_switch_prepare(struct gb_connection *connection);
-void gb_connection_mode_switch_complete(struct gb_connection *connection);
-
-void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id,
- u8 *data, size_t length);
-
-void gb_connection_latency_tag_enable(struct gb_connection *connection);
-void gb_connection_latency_tag_disable(struct gb_connection *connection);
-
-static inline bool gb_connection_e2efc_enabled(struct gb_connection *connection)
-{
- return !(connection->flags & GB_CONNECTION_FLAG_CSD);
-}
-
-static inline bool
-gb_connection_flow_control_disabled(struct gb_connection *connection)
-{
- return connection->flags & GB_CONNECTION_FLAG_NO_FLOWCTRL;
-}
-
-static inline bool gb_connection_is_offloaded(struct gb_connection *connection)
-{
- return connection->flags & GB_CONNECTION_FLAG_OFFLOADED;
-}
-
-static inline bool gb_connection_is_control(struct gb_connection *connection)
-{
- return connection->flags & GB_CONNECTION_FLAG_CONTROL;
-}
-
-static inline void *gb_connection_get_data(struct gb_connection *connection)
-{
- return connection->private;
-}
-
-static inline void gb_connection_set_data(struct gb_connection *connection,
- void *data)
-{
- connection->private = data;
-}
-
-#endif /* __CONNECTION_H */
diff --git a/drivers/staging/greybus/control.c b/drivers/staging/greybus/control.c
deleted file mode 100644
index a9e8b6036cac..000000000000
--- a/drivers/staging/greybus/control.c
+++ /dev/null
@@ -1,584 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus CPort control protocol.
- *
- * Copyright 2015 Google Inc.
- * Copyright 2015 Linaro Ltd.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include "greybus.h"
-
-/* Highest control-protocol version supported */
-#define GB_CONTROL_VERSION_MAJOR 0
-#define GB_CONTROL_VERSION_MINOR 1
-
-static int gb_control_get_version(struct gb_control *control)
-{
- struct gb_interface *intf = control->connection->intf;
- struct gb_control_version_request request;
- struct gb_control_version_response response;
- int ret;
-
- request.major = GB_CONTROL_VERSION_MAJOR;
- request.minor = GB_CONTROL_VERSION_MINOR;
-
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_VERSION,
- &request, sizeof(request), &response,
- sizeof(response));
- if (ret) {
- dev_err(&intf->dev,
- "failed to get control-protocol version: %d\n",
- ret);
- return ret;
- }
-
- if (response.major > request.major) {
- dev_err(&intf->dev,
- "unsupported major control-protocol version (%u > %u)\n",
- response.major, request.major);
- return -ENOTSUPP;
- }
-
- control->protocol_major = response.major;
- control->protocol_minor = response.minor;
-
- dev_dbg(&intf->dev, "%s - %u.%u\n", __func__, response.major,
- response.minor);
-
- return 0;
-}
-
-static int gb_control_get_bundle_version(struct gb_control *control,
- struct gb_bundle *bundle)
-{
- struct gb_interface *intf = control->connection->intf;
- struct gb_control_bundle_version_request request;
- struct gb_control_bundle_version_response response;
- int ret;
-
- request.bundle_id = bundle->id;
-
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_BUNDLE_VERSION,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret) {
- dev_err(&intf->dev,
- "failed to get bundle %u class version: %d\n",
- bundle->id, ret);
- return ret;
- }
-
- bundle->class_major = response.major;
- bundle->class_minor = response.minor;
-
- dev_dbg(&intf->dev, "%s - %u: %u.%u\n", __func__, bundle->id,
- response.major, response.minor);
-
- return 0;
-}
-
-int gb_control_get_bundle_versions(struct gb_control *control)
-{
- struct gb_interface *intf = control->connection->intf;
- struct gb_bundle *bundle;
- int ret;
-
- if (!control->has_bundle_version)
- return 0;
-
- list_for_each_entry(bundle, &intf->bundles, links) {
- ret = gb_control_get_bundle_version(control, bundle);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-/* Get Manifest's size from the interface */
-int gb_control_get_manifest_size_operation(struct gb_interface *intf)
-{
- struct gb_control_get_manifest_size_response response;
- struct gb_connection *connection = intf->control->connection;
- int ret;
-
- ret = gb_operation_sync(connection, GB_CONTROL_TYPE_GET_MANIFEST_SIZE,
- NULL, 0, &response, sizeof(response));
- if (ret) {
- dev_err(&connection->intf->dev,
- "failed to get manifest size: %d\n", ret);
- return ret;
- }
-
- return le16_to_cpu(response.size);
-}
-
-/* Reads Manifest from the interface */
-int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
- size_t size)
-{
- struct gb_connection *connection = intf->control->connection;
-
- return gb_operation_sync(connection, GB_CONTROL_TYPE_GET_MANIFEST,
- NULL, 0, manifest, size);
-}
-
-int gb_control_connected_operation(struct gb_control *control, u16 cport_id)
-{
- struct gb_control_connected_request request;
-
- request.cport_id = cpu_to_le16(cport_id);
- return gb_operation_sync(control->connection, GB_CONTROL_TYPE_CONNECTED,
- &request, sizeof(request), NULL, 0);
-}
-
-int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id)
-{
- struct gb_control_disconnected_request request;
-
- request.cport_id = cpu_to_le16(cport_id);
- return gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_DISCONNECTED, &request,
- sizeof(request), NULL, 0);
-}
-
-int gb_control_disconnecting_operation(struct gb_control *control,
- u16 cport_id)
-{
- struct gb_control_disconnecting_request *request;
- struct gb_operation *operation;
- int ret;
-
- operation = gb_operation_create_core(control->connection,
- GB_CONTROL_TYPE_DISCONNECTING,
- sizeof(*request), 0, 0,
- GFP_KERNEL);
- if (!operation)
- return -ENOMEM;
-
- request = operation->request->payload;
- request->cport_id = cpu_to_le16(cport_id);
-
- ret = gb_operation_request_send_sync(operation);
- if (ret) {
- dev_err(&control->dev, "failed to send disconnecting: %d\n",
- ret);
- }
-
- gb_operation_put(operation);
-
- return ret;
-}
-
-int gb_control_mode_switch_operation(struct gb_control *control)
-{
- struct gb_operation *operation;
- int ret;
-
- operation = gb_operation_create_core(control->connection,
- GB_CONTROL_TYPE_MODE_SWITCH,
- 0, 0,
- GB_OPERATION_FLAG_UNIDIRECTIONAL,
- GFP_KERNEL);
- if (!operation)
- return -ENOMEM;
-
- ret = gb_operation_request_send_sync(operation);
- if (ret)
- dev_err(&control->dev, "failed to send mode switch: %d\n", ret);
-
- gb_operation_put(operation);
-
- return ret;
-}
-
-static int gb_control_bundle_pm_status_map(u8 status)
-{
- switch (status) {
- case GB_CONTROL_BUNDLE_PM_INVAL:
- return -EINVAL;
- case GB_CONTROL_BUNDLE_PM_BUSY:
- return -EBUSY;
- case GB_CONTROL_BUNDLE_PM_NA:
- return -ENOMSG;
- case GB_CONTROL_BUNDLE_PM_FAIL:
- default:
- return -EREMOTEIO;
- }
-}
-
-int gb_control_bundle_suspend(struct gb_control *control, u8 bundle_id)
-{
- struct gb_control_bundle_pm_request request;
- struct gb_control_bundle_pm_response response;
- int ret;
-
- request.bundle_id = bundle_id;
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_BUNDLE_SUSPEND, &request,
- sizeof(request), &response, sizeof(response));
- if (ret) {
- dev_err(&control->dev, "failed to send bundle %u suspend: %d\n",
- bundle_id, ret);
- return ret;
- }
-
- if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
- dev_err(&control->dev, "failed to suspend bundle %u: %d\n",
- bundle_id, response.status);
- return gb_control_bundle_pm_status_map(response.status);
- }
-
- return 0;
-}
-
-int gb_control_bundle_resume(struct gb_control *control, u8 bundle_id)
-{
- struct gb_control_bundle_pm_request request;
- struct gb_control_bundle_pm_response response;
- int ret;
-
- request.bundle_id = bundle_id;
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_BUNDLE_RESUME, &request,
- sizeof(request), &response, sizeof(response));
- if (ret) {
- dev_err(&control->dev, "failed to send bundle %u resume: %d\n",
- bundle_id, ret);
- return ret;
- }
-
- if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
- dev_err(&control->dev, "failed to resume bundle %u: %d\n",
- bundle_id, response.status);
- return gb_control_bundle_pm_status_map(response.status);
- }
-
- return 0;
-}
-
-int gb_control_bundle_deactivate(struct gb_control *control, u8 bundle_id)
-{
- struct gb_control_bundle_pm_request request;
- struct gb_control_bundle_pm_response response;
- int ret;
-
- request.bundle_id = bundle_id;
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_BUNDLE_DEACTIVATE, &request,
- sizeof(request), &response, sizeof(response));
- if (ret) {
- dev_err(&control->dev,
- "failed to send bundle %u deactivate: %d\n", bundle_id,
- ret);
- return ret;
- }
-
- if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
- dev_err(&control->dev, "failed to deactivate bundle %u: %d\n",
- bundle_id, response.status);
- return gb_control_bundle_pm_status_map(response.status);
- }
-
- return 0;
-}
-
-int gb_control_bundle_activate(struct gb_control *control, u8 bundle_id)
-{
- struct gb_control_bundle_pm_request request;
- struct gb_control_bundle_pm_response response;
- int ret;
-
- if (!control->has_bundle_activate)
- return 0;
-
- request.bundle_id = bundle_id;
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_BUNDLE_ACTIVATE, &request,
- sizeof(request), &response, sizeof(response));
- if (ret) {
- dev_err(&control->dev,
- "failed to send bundle %u activate: %d\n", bundle_id,
- ret);
- return ret;
- }
-
- if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
- dev_err(&control->dev, "failed to activate bundle %u: %d\n",
- bundle_id, response.status);
- return gb_control_bundle_pm_status_map(response.status);
- }
-
- return 0;
-}
-
-static int gb_control_interface_pm_status_map(u8 status)
-{
- switch (status) {
- case GB_CONTROL_INTF_PM_BUSY:
- return -EBUSY;
- case GB_CONTROL_INTF_PM_NA:
- return -ENOMSG;
- default:
- return -EREMOTEIO;
- }
-}
-
-int gb_control_interface_suspend_prepare(struct gb_control *control)
-{
- struct gb_control_intf_pm_response response;
- int ret;
-
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_INTF_SUSPEND_PREPARE, NULL, 0,
- &response, sizeof(response));
- if (ret) {
- dev_err(&control->dev,
- "failed to send interface suspend prepare: %d\n", ret);
- return ret;
- }
-
- if (response.status != GB_CONTROL_INTF_PM_OK) {
- dev_err(&control->dev, "interface error while preparing suspend: %d\n",
- response.status);
- return gb_control_interface_pm_status_map(response.status);
- }
-
- return 0;
-}
-
-int gb_control_interface_deactivate_prepare(struct gb_control *control)
-{
- struct gb_control_intf_pm_response response;
- int ret;
-
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_INTF_DEACTIVATE_PREPARE, NULL,
- 0, &response, sizeof(response));
- if (ret) {
- dev_err(&control->dev, "failed to send interface deactivate prepare: %d\n",
- ret);
- return ret;
- }
-
- if (response.status != GB_CONTROL_INTF_PM_OK) {
- dev_err(&control->dev, "interface error while preparing deactivate: %d\n",
- response.status);
- return gb_control_interface_pm_status_map(response.status);
- }
-
- return 0;
-}
-
-int gb_control_interface_hibernate_abort(struct gb_control *control)
-{
- struct gb_control_intf_pm_response response;
- int ret;
-
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_INTF_HIBERNATE_ABORT, NULL, 0,
- &response, sizeof(response));
- if (ret) {
- dev_err(&control->dev,
- "failed to send interface aborting hibernate: %d\n",
- ret);
- return ret;
- }
-
- if (response.status != GB_CONTROL_INTF_PM_OK) {
- dev_err(&control->dev, "interface error while aborting hibernate: %d\n",
- response.status);
- return gb_control_interface_pm_status_map(response.status);
- }
-
- return 0;
-}
-
-static ssize_t vendor_string_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_control *control = to_gb_control(dev);
-
- return scnprintf(buf, PAGE_SIZE, "%s\n", control->vendor_string);
-}
-static DEVICE_ATTR_RO(vendor_string);
-
-static ssize_t product_string_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_control *control = to_gb_control(dev);
-
- return scnprintf(buf, PAGE_SIZE, "%s\n", control->product_string);
-}
-static DEVICE_ATTR_RO(product_string);
-
-static struct attribute *control_attrs[] = {
- &dev_attr_vendor_string.attr,
- &dev_attr_product_string.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(control);
-
-static void gb_control_release(struct device *dev)
-{
- struct gb_control *control = to_gb_control(dev);
-
- gb_connection_destroy(control->connection);
-
- kfree(control->vendor_string);
- kfree(control->product_string);
-
- kfree(control);
-}
-
-struct device_type greybus_control_type = {
- .name = "greybus_control",
- .release = gb_control_release,
-};
-
-struct gb_control *gb_control_create(struct gb_interface *intf)
-{
- struct gb_connection *connection;
- struct gb_control *control;
-
- control = kzalloc(sizeof(*control), GFP_KERNEL);
- if (!control)
- return ERR_PTR(-ENOMEM);
-
- control->intf = intf;
-
- connection = gb_connection_create_control(intf);
- if (IS_ERR(connection)) {
- dev_err(&intf->dev,
- "failed to create control connection: %ld\n",
- PTR_ERR(connection));
- kfree(control);
- return ERR_CAST(connection);
- }
-
- control->connection = connection;
-
- control->dev.parent = &intf->dev;
- control->dev.bus = &greybus_bus_type;
- control->dev.type = &greybus_control_type;
- control->dev.groups = control_groups;
- control->dev.dma_mask = intf->dev.dma_mask;
- device_initialize(&control->dev);
- dev_set_name(&control->dev, "%s.ctrl", dev_name(&intf->dev));
-
- gb_connection_set_data(control->connection, control);
-
- return control;
-}
-
-int gb_control_enable(struct gb_control *control)
-{
- int ret;
-
- dev_dbg(&control->connection->intf->dev, "%s\n", __func__);
-
- ret = gb_connection_enable_tx(control->connection);
- if (ret) {
- dev_err(&control->connection->intf->dev,
- "failed to enable control connection: %d\n",
- ret);
- return ret;
- }
-
- ret = gb_control_get_version(control);
- if (ret)
- goto err_disable_connection;
-
- if (control->protocol_major > 0 || control->protocol_minor > 1)
- control->has_bundle_version = true;
-
- /* FIXME: use protocol version instead */
- if (!(control->intf->quirks & GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE))
- control->has_bundle_activate = true;
-
- return 0;
-
-err_disable_connection:
- gb_connection_disable(control->connection);
-
- return ret;
-}
-
-void gb_control_disable(struct gb_control *control)
-{
- dev_dbg(&control->connection->intf->dev, "%s\n", __func__);
-
- if (control->intf->disconnected)
- gb_connection_disable_forced(control->connection);
- else
- gb_connection_disable(control->connection);
-}
-
-int gb_control_suspend(struct gb_control *control)
-{
- gb_connection_disable(control->connection);
-
- return 0;
-}
-
-int gb_control_resume(struct gb_control *control)
-{
- int ret;
-
- ret = gb_connection_enable_tx(control->connection);
- if (ret) {
- dev_err(&control->connection->intf->dev,
- "failed to enable control connection: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-int gb_control_add(struct gb_control *control)
-{
- int ret;
-
- ret = device_add(&control->dev);
- if (ret) {
- dev_err(&control->dev,
- "failed to register control device: %d\n",
- ret);
- return ret;
- }
-
- return 0;
-}
-
-void gb_control_del(struct gb_control *control)
-{
- if (device_is_registered(&control->dev))
- device_del(&control->dev);
-}
-
-struct gb_control *gb_control_get(struct gb_control *control)
-{
- get_device(&control->dev);
-
- return control;
-}
-
-void gb_control_put(struct gb_control *control)
-{
- put_device(&control->dev);
-}
-
-void gb_control_mode_switch_prepare(struct gb_control *control)
-{
- gb_connection_mode_switch_prepare(control->connection);
-}
-
-void gb_control_mode_switch_complete(struct gb_control *control)
-{
- gb_connection_mode_switch_complete(control->connection);
-}
diff --git a/drivers/staging/greybus/control.h b/drivers/staging/greybus/control.h
deleted file mode 100644
index 3a29ec05f631..000000000000
--- a/drivers/staging/greybus/control.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Greybus CPort control protocol
- *
- * Copyright 2015 Google Inc.
- * Copyright 2015 Linaro Ltd.
- */
-
-#ifndef __CONTROL_H
-#define __CONTROL_H
-
-struct gb_control {
- struct device dev;
- struct gb_interface *intf;
-
- struct gb_connection *connection;
-
- u8 protocol_major;
- u8 protocol_minor;
-
- bool has_bundle_activate;
- bool has_bundle_version;
-
- char *vendor_string;
- char *product_string;
-};
-#define to_gb_control(d) container_of(d, struct gb_control, dev)
-
-struct gb_control *gb_control_create(struct gb_interface *intf);
-int gb_control_enable(struct gb_control *control);
-void gb_control_disable(struct gb_control *control);
-int gb_control_suspend(struct gb_control *control);
-int gb_control_resume(struct gb_control *control);
-int gb_control_add(struct gb_control *control);
-void gb_control_del(struct gb_control *control);
-struct gb_control *gb_control_get(struct gb_control *control);
-void gb_control_put(struct gb_control *control);
-
-int gb_control_get_bundle_versions(struct gb_control *control);
-int gb_control_connected_operation(struct gb_control *control, u16 cport_id);
-int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id);
-int gb_control_disconnecting_operation(struct gb_control *control,
- u16 cport_id);
-int gb_control_mode_switch_operation(struct gb_control *control);
-void gb_control_mode_switch_prepare(struct gb_control *control);
-void gb_control_mode_switch_complete(struct gb_control *control);
-int gb_control_get_manifest_size_operation(struct gb_interface *intf);
-int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
- size_t size);
-int gb_control_bundle_suspend(struct gb_control *control, u8 bundle_id);
-int gb_control_bundle_resume(struct gb_control *control, u8 bundle_id);
-int gb_control_bundle_deactivate(struct gb_control *control, u8 bundle_id);
-int gb_control_bundle_activate(struct gb_control *control, u8 bundle_id);
-int gb_control_interface_suspend_prepare(struct gb_control *control);
-int gb_control_interface_deactivate_prepare(struct gb_control *control);
-int gb_control_interface_hibernate_abort(struct gb_control *control);
-#endif /* __CONTROL_H */
diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c
deleted file mode 100644
index d6b0d49130c0..000000000000
--- a/drivers/staging/greybus/core.c
+++ /dev/null
@@ -1,349 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus "Core"
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define CREATE_TRACE_POINTS
-#include "greybus.h"
-#include "greybus_trace.h"
-
-#define GB_BUNDLE_AUTOSUSPEND_MS 3000
-
-/* Allow greybus to be disabled at boot if needed */
-static bool nogreybus;
-#ifdef MODULE
-module_param(nogreybus, bool, 0444);
-#else
-core_param(nogreybus, nogreybus, bool, 0444);
-#endif
-int greybus_disabled(void)
-{
- return nogreybus;
-}
-EXPORT_SYMBOL_GPL(greybus_disabled);
-
-static bool greybus_match_one_id(struct gb_bundle *bundle,
- const struct greybus_bundle_id *id)
-{
- if ((id->match_flags & GREYBUS_ID_MATCH_VENDOR) &&
- (id->vendor != bundle->intf->vendor_id))
- return false;
-
- if ((id->match_flags & GREYBUS_ID_MATCH_PRODUCT) &&
- (id->product != bundle->intf->product_id))
- return false;
-
- if ((id->match_flags & GREYBUS_ID_MATCH_CLASS) &&
- (id->class != bundle->class))
- return false;
-
- return true;
-}
-
-static const struct greybus_bundle_id *
-greybus_match_id(struct gb_bundle *bundle, const struct greybus_bundle_id *id)
-{
- if (!id)
- return NULL;
-
- for (; id->vendor || id->product || id->class || id->driver_info;
- id++) {
- if (greybus_match_one_id(bundle, id))
- return id;
- }
-
- return NULL;
-}
-
-static int greybus_match_device(struct device *dev, struct device_driver *drv)
-{
- struct greybus_driver *driver = to_greybus_driver(drv);
- struct gb_bundle *bundle;
- const struct greybus_bundle_id *id;
-
- if (!is_gb_bundle(dev))
- return 0;
-
- bundle = to_gb_bundle(dev);
-
- id = greybus_match_id(bundle, driver->id_table);
- if (id)
- return 1;
- /* FIXME - Dynamic ids? */
- return 0;
-}
-
-static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct gb_host_device *hd;
- struct gb_module *module = NULL;
- struct gb_interface *intf = NULL;
- struct gb_control *control = NULL;
- struct gb_bundle *bundle = NULL;
- struct gb_svc *svc = NULL;
-
- if (is_gb_host_device(dev)) {
- hd = to_gb_host_device(dev);
- } else if (is_gb_module(dev)) {
- module = to_gb_module(dev);
- hd = module->hd;
- } else if (is_gb_interface(dev)) {
- intf = to_gb_interface(dev);
- module = intf->module;
- hd = intf->hd;
- } else if (is_gb_control(dev)) {
- control = to_gb_control(dev);
- intf = control->intf;
- module = intf->module;
- hd = intf->hd;
- } else if (is_gb_bundle(dev)) {
- bundle = to_gb_bundle(dev);
- intf = bundle->intf;
- module = intf->module;
- hd = intf->hd;
- } else if (is_gb_svc(dev)) {
- svc = to_gb_svc(dev);
- hd = svc->hd;
- } else {
- dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
- return -EINVAL;
- }
-
- if (add_uevent_var(env, "BUS=%u", hd->bus_id))
- return -ENOMEM;
-
- if (module) {
- if (add_uevent_var(env, "MODULE=%u", module->module_id))
- return -ENOMEM;
- }
-
- if (intf) {
- if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
- return -ENOMEM;
- if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",
- intf->vendor_id, intf->product_id))
- return -ENOMEM;
- }
-
- if (bundle) {
- // FIXME
- // add a uevent that can "load" a bundle type
- // This is what we need to bind a driver to so use the info
- // in gmod here as well
-
- if (add_uevent_var(env, "BUNDLE=%u", bundle->id))
- return -ENOMEM;
- if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void greybus_shutdown(struct device *dev)
-{
- if (is_gb_host_device(dev)) {
- struct gb_host_device *hd;
-
- hd = to_gb_host_device(dev);
- gb_hd_shutdown(hd);
- }
-}
-
-struct bus_type greybus_bus_type = {
- .name = "greybus",
- .match = greybus_match_device,
- .uevent = greybus_uevent,
- .shutdown = greybus_shutdown,
-};
-
-static int greybus_probe(struct device *dev)
-{
- struct greybus_driver *driver = to_greybus_driver(dev->driver);
- struct gb_bundle *bundle = to_gb_bundle(dev);
- const struct greybus_bundle_id *id;
- int retval;
-
- /* match id */
- id = greybus_match_id(bundle, driver->id_table);
- if (!id)
- return -ENODEV;
-
- retval = pm_runtime_get_sync(&bundle->intf->dev);
- if (retval < 0) {
- pm_runtime_put_noidle(&bundle->intf->dev);
- return retval;
- }
-
- retval = gb_control_bundle_activate(bundle->intf->control, bundle->id);
- if (retval) {
- pm_runtime_put(&bundle->intf->dev);
- return retval;
- }
-
- /*
- * Unbound bundle devices are always deactivated. During probe, the
- * Runtime PM is set to enabled and active and the usage count is
- * incremented. If the driver supports runtime PM, it should call
- * pm_runtime_put() in its probe routine and pm_runtime_get_sync()
- * in remove routine.
- */
- pm_runtime_set_autosuspend_delay(dev, GB_BUNDLE_AUTOSUSPEND_MS);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_get_noresume(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
-
- retval = driver->probe(bundle, id);
- if (retval) {
- /*
- * Catch buggy drivers that fail to destroy their connections.
- */
- WARN_ON(!list_empty(&bundle->connections));
-
- gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
-
- pm_runtime_disable(dev);
- pm_runtime_set_suspended(dev);
- pm_runtime_put_noidle(dev);
- pm_runtime_dont_use_autosuspend(dev);
- pm_runtime_put(&bundle->intf->dev);
-
- return retval;
- }
-
- pm_runtime_put(&bundle->intf->dev);
-
- return 0;
-}
-
-static int greybus_remove(struct device *dev)
-{
- struct greybus_driver *driver = to_greybus_driver(dev->driver);
- struct gb_bundle *bundle = to_gb_bundle(dev);
- struct gb_connection *connection;
- int retval;
-
- retval = pm_runtime_get_sync(dev);
- if (retval < 0)
- dev_err(dev, "failed to resume bundle: %d\n", retval);
-
- /*
- * Disable (non-offloaded) connections early in case the interface is
- * already gone to avoid unceccessary operation timeouts during
- * driver disconnect. Otherwise, only disable incoming requests.
- */
- list_for_each_entry(connection, &bundle->connections, bundle_links) {
- if (gb_connection_is_offloaded(connection))
- continue;
-
- if (bundle->intf->disconnected)
- gb_connection_disable_forced(connection);
- else
- gb_connection_disable_rx(connection);
- }
-
- driver->disconnect(bundle);
-
- /* Catch buggy drivers that fail to destroy their connections. */
- WARN_ON(!list_empty(&bundle->connections));
-
- if (!bundle->intf->disconnected)
- gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
-
- pm_runtime_put_noidle(dev);
- pm_runtime_disable(dev);
- pm_runtime_set_suspended(dev);
- pm_runtime_dont_use_autosuspend(dev);
- pm_runtime_put_noidle(dev);
-
- return 0;
-}
-
-int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
- const char *mod_name)
-{
- int retval;
-
- if (greybus_disabled())
- return -ENODEV;
-
- driver->driver.bus = &greybus_bus_type;
- driver->driver.name = driver->name;
- driver->driver.probe = greybus_probe;
- driver->driver.remove = greybus_remove;
- driver->driver.owner = owner;
- driver->driver.mod_name = mod_name;
-
- retval = driver_register(&driver->driver);
- if (retval)
- return retval;
-
- pr_info("registered new driver %s\n", driver->name);
- return 0;
-}
-EXPORT_SYMBOL_GPL(greybus_register_driver);
-
-void greybus_deregister_driver(struct greybus_driver *driver)
-{
- driver_unregister(&driver->driver);
-}
-EXPORT_SYMBOL_GPL(greybus_deregister_driver);
-
-static int __init gb_init(void)
-{
- int retval;
-
- if (greybus_disabled())
- return -ENODEV;
-
- BUILD_BUG_ON(CPORT_ID_MAX >= (long)CPORT_ID_BAD);
-
- gb_debugfs_init();
-
- retval = bus_register(&greybus_bus_type);
- if (retval) {
- pr_err("bus_register failed (%d)\n", retval);
- goto error_bus;
- }
-
- retval = gb_hd_init();
- if (retval) {
- pr_err("gb_hd_init failed (%d)\n", retval);
- goto error_hd;
- }
-
- retval = gb_operation_init();
- if (retval) {
- pr_err("gb_operation_init failed (%d)\n", retval);
- goto error_operation;
- }
- return 0; /* Success */
-
-error_operation:
- gb_hd_exit();
-error_hd:
- bus_unregister(&greybus_bus_type);
-error_bus:
- gb_debugfs_cleanup();
-
- return retval;
-}
-module_init(gb_init);
-
-static void __exit gb_exit(void)
-{
- gb_operation_exit();
- gb_hd_exit();
- bus_unregister(&greybus_bus_type);
- gb_debugfs_cleanup();
- tracepoint_synchronize_unregister();
-}
-module_exit(gb_exit);
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
diff --git a/drivers/staging/greybus/debugfs.c b/drivers/staging/greybus/debugfs.c
deleted file mode 100644
index 56e20c30feb5..000000000000
--- a/drivers/staging/greybus/debugfs.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus debugfs code
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- */
-
-#include <linux/debugfs.h>
-
-#include "greybus.h"
-
-static struct dentry *gb_debug_root;
-
-void __init gb_debugfs_init(void)
-{
- gb_debug_root = debugfs_create_dir("greybus", NULL);
-}
-
-void gb_debugfs_cleanup(void)
-{
- debugfs_remove_recursive(gb_debug_root);
- gb_debug_root = NULL;
-}
-
-struct dentry *gb_debugfs_get(void)
-{
- return gb_debug_root;
-}
-EXPORT_SYMBOL_GPL(gb_debugfs_get);
diff --git a/drivers/staging/greybus/es2.c b/drivers/staging/greybus/es2.c
deleted file mode 100644
index be6af18cec31..000000000000
--- a/drivers/staging/greybus/es2.c
+++ /dev/null
@@ -1,1466 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus "AP" USB driver for "ES2" controller chips
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- */
-#include <linux/kthread.h>
-#include <linux/sizes.h>
-#include <linux/usb.h>
-#include <linux/kfifo.h>
-#include <linux/debugfs.h>
-#include <linux/list.h>
-#include <asm/unaligned.h>
-
-#include "arpc.h"
-#include "greybus.h"
-#include "greybus_trace.h"
-#include "connection.h"
-
-
-/* Default timeout for USB vendor requests. */
-#define ES2_USB_CTRL_TIMEOUT 500
-
-/* Default timeout for ARPC CPort requests */
-#define ES2_ARPC_CPORT_TIMEOUT 500
-
-/* Fixed CPort numbers */
-#define ES2_CPORT_CDSI0 16
-#define ES2_CPORT_CDSI1 17
-
-/* Memory sizes for the buffers sent to/from the ES2 controller */
-#define ES2_GBUF_MSG_SIZE_MAX 2048
-
-/* Memory sizes for the ARPC buffers */
-#define ARPC_OUT_SIZE_MAX U16_MAX
-#define ARPC_IN_SIZE_MAX 128
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x18d1, 0x1eaf) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-#define APB1_LOG_SIZE SZ_16K
-
-/*
- * Number of CPort IN urbs in flight at any point in time.
- * Adjust if we are having stalls in the USB buffer due to not enough urbs in
- * flight.
- */
-#define NUM_CPORT_IN_URB 4
-
-/* Number of CPort OUT urbs in flight at any point in time.
- * Adjust if we get messages saying we are out of urbs in the system log.
- */
-#define NUM_CPORT_OUT_URB 8
-
-/*
- * Number of ARPC in urbs in flight at any point in time.
- */
-#define NUM_ARPC_IN_URB 2
-
-/*
- * @endpoint: bulk in endpoint for CPort data
- * @urb: array of urbs for the CPort in messages
- * @buffer: array of buffers for the @cport_in_urb urbs
- */
-struct es2_cport_in {
- __u8 endpoint;
- struct urb *urb[NUM_CPORT_IN_URB];
- u8 *buffer[NUM_CPORT_IN_URB];
-};
-
-/**
- * es2_ap_dev - ES2 USB Bridge to AP structure
- * @usb_dev: pointer to the USB device we are.
- * @usb_intf: pointer to the USB interface we are bound to.
- * @hd: pointer to our gb_host_device structure
-
- * @cport_in: endpoint, urbs and buffer for cport in messages
- * @cport_out_endpoint: endpoint for for cport out messages
- * @cport_out_urb: array of urbs for the CPort out messages
- * @cport_out_urb_busy: array of flags to see if the @cport_out_urb is busy or
- * not.
- * @cport_out_urb_cancelled: array of flags indicating whether the
- * corresponding @cport_out_urb is being cancelled
- * @cport_out_urb_lock: locks the @cport_out_urb_busy "list"
- *
- * @apb_log_task: task pointer for logging thread
- * @apb_log_dentry: file system entry for the log file interface
- * @apb_log_enable_dentry: file system entry for enabling logging
- * @apb_log_fifo: kernel FIFO to carry logged data
- * @arpc_urb: array of urbs for the ARPC in messages
- * @arpc_buffer: array of buffers for the @arpc_urb urbs
- * @arpc_endpoint_in: bulk in endpoint for APBridgeA RPC
- * @arpc_id_cycle: gives an unique id to ARPC
- * @arpc_lock: locks ARPC list
- * @arpcs: list of in progress ARPCs
- */
-struct es2_ap_dev {
- struct usb_device *usb_dev;
- struct usb_interface *usb_intf;
- struct gb_host_device *hd;
-
- struct es2_cport_in cport_in;
- __u8 cport_out_endpoint;
- struct urb *cport_out_urb[NUM_CPORT_OUT_URB];
- bool cport_out_urb_busy[NUM_CPORT_OUT_URB];
- bool cport_out_urb_cancelled[NUM_CPORT_OUT_URB];
- spinlock_t cport_out_urb_lock;
-
- bool cdsi1_in_use;
-
- struct task_struct *apb_log_task;
- struct dentry *apb_log_dentry;
- struct dentry *apb_log_enable_dentry;
- DECLARE_KFIFO(apb_log_fifo, char, APB1_LOG_SIZE);
-
- __u8 arpc_endpoint_in;
- struct urb *arpc_urb[NUM_ARPC_IN_URB];
- u8 *arpc_buffer[NUM_ARPC_IN_URB];
-
- int arpc_id_cycle;
- spinlock_t arpc_lock;
- struct list_head arpcs;
-};
-
-struct arpc {
- struct list_head list;
- struct arpc_request_message *req;
- struct arpc_response_message *resp;
- struct completion response_received;
- bool active;
-};
-
-static inline struct es2_ap_dev *hd_to_es2(struct gb_host_device *hd)
-{
- return (struct es2_ap_dev *)&hd->hd_priv;
-}
-
-static void cport_out_callback(struct urb *urb);
-static void usb_log_enable(struct es2_ap_dev *es2);
-static void usb_log_disable(struct es2_ap_dev *es2);
-static int arpc_sync(struct es2_ap_dev *es2, u8 type, void *payload,
- size_t size, int *result, unsigned int timeout);
-
-static int output_sync(struct es2_ap_dev *es2, void *req, u16 size, u8 cmd)
-{
- struct usb_device *udev = es2->usb_dev;
- u8 *data;
- int retval;
-
- data = kmemdup(req, size, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- cmd,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE,
- 0, 0, data, size, ES2_USB_CTRL_TIMEOUT);
- if (retval < 0)
- dev_err(&udev->dev, "%s: return error %d\n", __func__, retval);
- else
- retval = 0;
-
- kfree(data);
- return retval;
-}
-
-static void ap_urb_complete(struct urb *urb)
-{
- struct usb_ctrlrequest *dr = urb->context;
-
- kfree(dr);
- usb_free_urb(urb);
-}
-
-static int output_async(struct es2_ap_dev *es2, void *req, u16 size, u8 cmd)
-{
- struct usb_device *udev = es2->usb_dev;
- struct urb *urb;
- struct usb_ctrlrequest *dr;
- u8 *buf;
- int retval;
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb)
- return -ENOMEM;
-
- dr = kmalloc(sizeof(*dr) + size, GFP_ATOMIC);
- if (!dr) {
- usb_free_urb(urb);
- return -ENOMEM;
- }
-
- buf = (u8 *)dr + sizeof(*dr);
- memcpy(buf, req, size);
-
- dr->bRequest = cmd;
- dr->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
- dr->wValue = 0;
- dr->wIndex = 0;
- dr->wLength = cpu_to_le16(size);
-
- usb_fill_control_urb(urb, udev, usb_sndctrlpipe(udev, 0),
- (unsigned char *)dr, buf, size,
- ap_urb_complete, dr);
- retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval) {
- usb_free_urb(urb);
- kfree(dr);
- }
- return retval;
-}
-
-static int output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
- bool async)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
-
- if (async)
- return output_async(es2, req, size, cmd);
-
- return output_sync(es2, req, size, cmd);
-}
-
-static int es2_cport_in_enable(struct es2_ap_dev *es2,
- struct es2_cport_in *cport_in)
-{
- struct urb *urb;
- int ret;
- int i;
-
- for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
- urb = cport_in->urb[i];
-
- ret = usb_submit_urb(urb, GFP_KERNEL);
- if (ret) {
- dev_err(&es2->usb_dev->dev,
- "failed to submit in-urb: %d\n", ret);
- goto err_kill_urbs;
- }
- }
-
- return 0;
-
-err_kill_urbs:
- for (--i; i >= 0; --i) {
- urb = cport_in->urb[i];
- usb_kill_urb(urb);
- }
-
- return ret;
-}
-
-static void es2_cport_in_disable(struct es2_ap_dev *es2,
- struct es2_cport_in *cport_in)
-{
- struct urb *urb;
- int i;
-
- for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
- urb = cport_in->urb[i];
- usb_kill_urb(urb);
- }
-}
-
-static int es2_arpc_in_enable(struct es2_ap_dev *es2)
-{
- struct urb *urb;
- int ret;
- int i;
-
- for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
- urb = es2->arpc_urb[i];
-
- ret = usb_submit_urb(urb, GFP_KERNEL);
- if (ret) {
- dev_err(&es2->usb_dev->dev,
- "failed to submit arpc in-urb: %d\n", ret);
- goto err_kill_urbs;
- }
- }
-
- return 0;
-
-err_kill_urbs:
- for (--i; i >= 0; --i) {
- urb = es2->arpc_urb[i];
- usb_kill_urb(urb);
- }
-
- return ret;
-}
-
-static void es2_arpc_in_disable(struct es2_ap_dev *es2)
-{
- struct urb *urb;
- int i;
-
- for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
- urb = es2->arpc_urb[i];
- usb_kill_urb(urb);
- }
-}
-
-static struct urb *next_free_urb(struct es2_ap_dev *es2, gfp_t gfp_mask)
-{
- struct urb *urb = NULL;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
-
- /* Look in our pool of allocated urbs first, as that's the "fastest" */
- for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
- if (!es2->cport_out_urb_busy[i] &&
- !es2->cport_out_urb_cancelled[i]) {
- es2->cport_out_urb_busy[i] = true;
- urb = es2->cport_out_urb[i];
- break;
- }
- }
- spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
- if (urb)
- return urb;
-
- /*
- * Crap, pool is empty, complain to the syslog and go allocate one
- * dynamically as we have to succeed.
- */
- dev_dbg(&es2->usb_dev->dev,
- "No free CPort OUT urbs, having to dynamically allocate one!\n");
- return usb_alloc_urb(0, gfp_mask);
-}
-
-static void free_urb(struct es2_ap_dev *es2, struct urb *urb)
-{
- unsigned long flags;
- int i;
- /*
- * See if this was an urb in our pool, if so mark it "free", otherwise
- * we need to free it ourselves.
- */
- spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
- for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
- if (urb == es2->cport_out_urb[i]) {
- es2->cport_out_urb_busy[i] = false;
- urb = NULL;
- break;
- }
- }
- spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
-
- /* If urb is not NULL, then we need to free this urb */
- usb_free_urb(urb);
-}
-
-/*
- * We (ab)use the operation-message header pad bytes to transfer the
- * cport id in order to minimise overhead.
- */
-static void
-gb_message_cport_pack(struct gb_operation_msg_hdr *header, u16 cport_id)
-{
- header->pad[0] = cport_id;
-}
-
-/* Clear the pad bytes used for the CPort id */
-static void gb_message_cport_clear(struct gb_operation_msg_hdr *header)
-{
- header->pad[0] = 0;
-}
-
-/* Extract the CPort id packed into the header, and clear it */
-static u16 gb_message_cport_unpack(struct gb_operation_msg_hdr *header)
-{
- u16 cport_id = header->pad[0];
-
- gb_message_cport_clear(header);
-
- return cport_id;
-}
-
-/*
- * Returns zero if the message was successfully queued, or a negative errno
- * otherwise.
- */
-static int message_send(struct gb_host_device *hd, u16 cport_id,
- struct gb_message *message, gfp_t gfp_mask)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct usb_device *udev = es2->usb_dev;
- size_t buffer_size;
- int retval;
- struct urb *urb;
- unsigned long flags;
-
- /*
- * The data actually transferred will include an indication
- * of where the data should be sent. Do one last check of
- * the target CPort id before filling it in.
- */
- if (!cport_id_valid(hd, cport_id)) {
- dev_err(&udev->dev, "invalid cport %u\n", cport_id);
- return -EINVAL;
- }
-
- /* Find a free urb */
- urb = next_free_urb(es2, gfp_mask);
- if (!urb)
- return -ENOMEM;
-
- spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
- message->hcpriv = urb;
- spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
-
- /* Pack the cport id into the message header */
- gb_message_cport_pack(message->header, cport_id);
-
- buffer_size = sizeof(*message->header) + message->payload_size;
-
- usb_fill_bulk_urb(urb, udev,
- usb_sndbulkpipe(udev,
- es2->cport_out_endpoint),
- message->buffer, buffer_size,
- cport_out_callback, message);
- urb->transfer_flags |= URB_ZERO_PACKET;
-
- trace_gb_message_submit(message);
-
- retval = usb_submit_urb(urb, gfp_mask);
- if (retval) {
- dev_err(&udev->dev, "failed to submit out-urb: %d\n", retval);
-
- spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
- message->hcpriv = NULL;
- spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
-
- free_urb(es2, urb);
- gb_message_cport_clear(message->header);
-
- return retval;
- }
-
- return 0;
-}
-
-/*
- * Can not be called in atomic context.
- */
-static void message_cancel(struct gb_message *message)
-{
- struct gb_host_device *hd = message->operation->connection->hd;
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct urb *urb;
- int i;
-
- might_sleep();
-
- spin_lock_irq(&es2->cport_out_urb_lock);
- urb = message->hcpriv;
-
- /* Prevent dynamically allocated urb from being deallocated. */
- usb_get_urb(urb);
-
- /* Prevent pre-allocated urb from being reused. */
- for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
- if (urb == es2->cport_out_urb[i]) {
- es2->cport_out_urb_cancelled[i] = true;
- break;
- }
- }
- spin_unlock_irq(&es2->cport_out_urb_lock);
-
- usb_kill_urb(urb);
-
- if (i < NUM_CPORT_OUT_URB) {
- spin_lock_irq(&es2->cport_out_urb_lock);
- es2->cport_out_urb_cancelled[i] = false;
- spin_unlock_irq(&es2->cport_out_urb_lock);
- }
-
- usb_free_urb(urb);
-}
-
-static int es2_cport_allocate(struct gb_host_device *hd, int cport_id,
- unsigned long flags)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct ida *id_map = &hd->cport_id_map;
- int ida_start, ida_end;
-
- switch (cport_id) {
- case ES2_CPORT_CDSI0:
- case ES2_CPORT_CDSI1:
- dev_err(&hd->dev, "cport %d not available\n", cport_id);
- return -EBUSY;
- }
-
- if (flags & GB_CONNECTION_FLAG_OFFLOADED &&
- flags & GB_CONNECTION_FLAG_CDSI1) {
- if (es2->cdsi1_in_use) {
- dev_err(&hd->dev, "CDSI1 already in use\n");
- return -EBUSY;
- }
-
- es2->cdsi1_in_use = true;
-
- return ES2_CPORT_CDSI1;
- }
-
- if (cport_id < 0) {
- ida_start = 0;
- ida_end = hd->num_cports;
- } else if (cport_id < hd->num_cports) {
- ida_start = cport_id;
- ida_end = cport_id + 1;
- } else {
- dev_err(&hd->dev, "cport %d not available\n", cport_id);
- return -EINVAL;
- }
-
- return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
-}
-
-static void es2_cport_release(struct gb_host_device *hd, u16 cport_id)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
-
- switch (cport_id) {
- case ES2_CPORT_CDSI1:
- es2->cdsi1_in_use = false;
- return;
- }
-
- ida_simple_remove(&hd->cport_id_map, cport_id);
-}
-
-static int cport_enable(struct gb_host_device *hd, u16 cport_id,
- unsigned long flags)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct usb_device *udev = es2->usb_dev;
- struct gb_apb_request_cport_flags *req;
- u32 connection_flags;
- int ret;
-
- req = kzalloc(sizeof(*req), GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
- connection_flags = 0;
- if (flags & GB_CONNECTION_FLAG_CONTROL)
- connection_flags |= GB_APB_CPORT_FLAG_CONTROL;
- if (flags & GB_CONNECTION_FLAG_HIGH_PRIO)
- connection_flags |= GB_APB_CPORT_FLAG_HIGH_PRIO;
-
- req->flags = cpu_to_le32(connection_flags);
-
- dev_dbg(&hd->dev, "%s - cport = %u, flags = %02x\n", __func__,
- cport_id, connection_flags);
-
- ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- GB_APB_REQUEST_CPORT_FLAGS,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE, cport_id, 0,
- req, sizeof(*req), ES2_USB_CTRL_TIMEOUT);
- if (ret != sizeof(*req)) {
- dev_err(&udev->dev, "failed to set cport flags for port %d\n",
- cport_id);
- if (ret >= 0)
- ret = -EIO;
-
- goto out;
- }
-
- ret = 0;
-out:
- kfree(req);
-
- return ret;
-}
-
-static int es2_cport_connected(struct gb_host_device *hd, u16 cport_id)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct device *dev = &es2->usb_dev->dev;
- struct arpc_cport_connected_req req;
- int ret;
-
- req.cport_id = cpu_to_le16(cport_id);
- ret = arpc_sync(es2, ARPC_TYPE_CPORT_CONNECTED, &req, sizeof(req),
- NULL, ES2_ARPC_CPORT_TIMEOUT);
- if (ret) {
- dev_err(dev, "failed to set connected state for cport %u: %d\n",
- cport_id, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int es2_cport_flush(struct gb_host_device *hd, u16 cport_id)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct device *dev = &es2->usb_dev->dev;
- struct arpc_cport_flush_req req;
- int ret;
-
- req.cport_id = cpu_to_le16(cport_id);
- ret = arpc_sync(es2, ARPC_TYPE_CPORT_FLUSH, &req, sizeof(req),
- NULL, ES2_ARPC_CPORT_TIMEOUT);
- if (ret) {
- dev_err(dev, "failed to flush cport %u: %d\n", cport_id, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int es2_cport_shutdown(struct gb_host_device *hd, u16 cport_id,
- u8 phase, unsigned int timeout)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct device *dev = &es2->usb_dev->dev;
- struct arpc_cport_shutdown_req req;
- int result;
- int ret;
-
- if (timeout > U16_MAX)
- return -EINVAL;
-
- req.cport_id = cpu_to_le16(cport_id);
- req.timeout = cpu_to_le16(timeout);
- req.phase = phase;
- ret = arpc_sync(es2, ARPC_TYPE_CPORT_SHUTDOWN, &req, sizeof(req),
- &result, ES2_ARPC_CPORT_TIMEOUT + timeout);
- if (ret) {
- dev_err(dev, "failed to send shutdown over cport %u: %d (%d)\n",
- cport_id, ret, result);
- return ret;
- }
-
- return 0;
-}
-
-static int es2_cport_quiesce(struct gb_host_device *hd, u16 cport_id,
- size_t peer_space, unsigned int timeout)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct device *dev = &es2->usb_dev->dev;
- struct arpc_cport_quiesce_req req;
- int result;
- int ret;
-
- if (peer_space > U16_MAX)
- return -EINVAL;
-
- if (timeout > U16_MAX)
- return -EINVAL;
-
- req.cport_id = cpu_to_le16(cport_id);
- req.peer_space = cpu_to_le16(peer_space);
- req.timeout = cpu_to_le16(timeout);
- ret = arpc_sync(es2, ARPC_TYPE_CPORT_QUIESCE, &req, sizeof(req),
- &result, ES2_ARPC_CPORT_TIMEOUT + timeout);
- if (ret) {
- dev_err(dev, "failed to quiesce cport %u: %d (%d)\n",
- cport_id, ret, result);
- return ret;
- }
-
- return 0;
-}
-
-static int es2_cport_clear(struct gb_host_device *hd, u16 cport_id)
-{
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct device *dev = &es2->usb_dev->dev;
- struct arpc_cport_clear_req req;
- int ret;
-
- req.cport_id = cpu_to_le16(cport_id);
- ret = arpc_sync(es2, ARPC_TYPE_CPORT_CLEAR, &req, sizeof(req),
- NULL, ES2_ARPC_CPORT_TIMEOUT);
- if (ret) {
- dev_err(dev, "failed to clear cport %u: %d\n", cport_id, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int latency_tag_enable(struct gb_host_device *hd, u16 cport_id)
-{
- int retval;
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct usb_device *udev = es2->usb_dev;
-
- retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- GB_APB_REQUEST_LATENCY_TAG_EN,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE, cport_id, 0, NULL,
- 0, ES2_USB_CTRL_TIMEOUT);
-
- if (retval < 0)
- dev_err(&udev->dev, "Cannot enable latency tag for cport %d\n",
- cport_id);
- return retval;
-}
-
-static int latency_tag_disable(struct gb_host_device *hd, u16 cport_id)
-{
- int retval;
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct usb_device *udev = es2->usb_dev;
-
- retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- GB_APB_REQUEST_LATENCY_TAG_DIS,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE, cport_id, 0, NULL,
- 0, ES2_USB_CTRL_TIMEOUT);
-
- if (retval < 0)
- dev_err(&udev->dev, "Cannot disable latency tag for cport %d\n",
- cport_id);
- return retval;
-}
-
-static struct gb_hd_driver es2_driver = {
- .hd_priv_size = sizeof(struct es2_ap_dev),
- .message_send = message_send,
- .message_cancel = message_cancel,
- .cport_allocate = es2_cport_allocate,
- .cport_release = es2_cport_release,
- .cport_enable = cport_enable,
- .cport_connected = es2_cport_connected,
- .cport_flush = es2_cport_flush,
- .cport_shutdown = es2_cport_shutdown,
- .cport_quiesce = es2_cport_quiesce,
- .cport_clear = es2_cport_clear,
- .latency_tag_enable = latency_tag_enable,
- .latency_tag_disable = latency_tag_disable,
- .output = output,
-};
-
-/* Common function to report consistent warnings based on URB status */
-static int check_urb_status(struct urb *urb)
-{
- struct device *dev = &urb->dev->dev;
- int status = urb->status;
-
- switch (status) {
- case 0:
- return 0;
-
- case -EOVERFLOW:
- dev_err(dev, "%s: overflow actual length is %d\n",
- __func__, urb->actual_length);
- /* fall through */
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- case -EILSEQ:
- case -EPROTO:
- /* device is gone, stop sending */
- return status;
- }
- dev_err(dev, "%s: unknown status %d\n", __func__, status);
-
- return -EAGAIN;
-}
-
-static void es2_destroy(struct es2_ap_dev *es2)
-{
- struct usb_device *udev;
- struct urb *urb;
- int i;
-
- debugfs_remove(es2->apb_log_enable_dentry);
- usb_log_disable(es2);
-
- /* Tear down everything! */
- for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
- urb = es2->cport_out_urb[i];
- usb_kill_urb(urb);
- usb_free_urb(urb);
- es2->cport_out_urb[i] = NULL;
- es2->cport_out_urb_busy[i] = false; /* just to be anal */
- }
-
- for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
- usb_free_urb(es2->arpc_urb[i]);
- kfree(es2->arpc_buffer[i]);
- es2->arpc_buffer[i] = NULL;
- }
-
- for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
- usb_free_urb(es2->cport_in.urb[i]);
- kfree(es2->cport_in.buffer[i]);
- es2->cport_in.buffer[i] = NULL;
- }
-
- /* release reserved CDSI0 and CDSI1 cports */
- gb_hd_cport_release_reserved(es2->hd, ES2_CPORT_CDSI1);
- gb_hd_cport_release_reserved(es2->hd, ES2_CPORT_CDSI0);
-
- udev = es2->usb_dev;
- gb_hd_put(es2->hd);
-
- usb_put_dev(udev);
-}
-
-static void cport_in_callback(struct urb *urb)
-{
- struct gb_host_device *hd = urb->context;
- struct device *dev = &urb->dev->dev;
- struct gb_operation_msg_hdr *header;
- int status = check_urb_status(urb);
- int retval;
- u16 cport_id;
-
- if (status) {
- if ((status == -EAGAIN) || (status == -EPROTO))
- goto exit;
-
- /* The urb is being unlinked */
- if (status == -ENOENT || status == -ESHUTDOWN)
- return;
-
- dev_err(dev, "urb cport in error %d (dropped)\n", status);
- return;
- }
-
- if (urb->actual_length < sizeof(*header)) {
- dev_err(dev, "short message received\n");
- goto exit;
- }
-
- /* Extract the CPort id, which is packed in the message header */
- header = urb->transfer_buffer;
- cport_id = gb_message_cport_unpack(header);
-
- if (cport_id_valid(hd, cport_id)) {
- greybus_data_rcvd(hd, cport_id, urb->transfer_buffer,
- urb->actual_length);
- } else {
- dev_err(dev, "invalid cport id %u received\n", cport_id);
- }
-exit:
- /* put our urb back in the request pool */
- retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval)
- dev_err(dev, "failed to resubmit in-urb: %d\n", retval);
-}
-
-static void cport_out_callback(struct urb *urb)
-{
- struct gb_message *message = urb->context;
- struct gb_host_device *hd = message->operation->connection->hd;
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- int status = check_urb_status(urb);
- unsigned long flags;
-
- gb_message_cport_clear(message->header);
-
- spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
- message->hcpriv = NULL;
- spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
-
- /*
- * Tell the submitter that the message send (attempt) is
- * complete, and report the status.
- */
- greybus_message_sent(hd, message, status);
-
- free_urb(es2, urb);
-}
-
-static struct arpc *arpc_alloc(void *payload, u16 size, u8 type)
-{
- struct arpc *rpc;
-
- if (size + sizeof(*rpc->req) > ARPC_OUT_SIZE_MAX)
- return NULL;
-
- rpc = kzalloc(sizeof(*rpc), GFP_KERNEL);
- if (!rpc)
- return NULL;
-
- INIT_LIST_HEAD(&rpc->list);
- rpc->req = kzalloc(sizeof(*rpc->req) + size, GFP_KERNEL);
- if (!rpc->req)
- goto err_free_rpc;
-
- rpc->resp = kzalloc(sizeof(*rpc->resp), GFP_KERNEL);
- if (!rpc->resp)
- goto err_free_req;
-
- rpc->req->type = type;
- rpc->req->size = cpu_to_le16(sizeof(*rpc->req) + size);
- memcpy(rpc->req->data, payload, size);
-
- init_completion(&rpc->response_received);
-
- return rpc;
-
-err_free_req:
- kfree(rpc->req);
-err_free_rpc:
- kfree(rpc);
-
- return NULL;
-}
-
-static void arpc_free(struct arpc *rpc)
-{
- kfree(rpc->req);
- kfree(rpc->resp);
- kfree(rpc);
-}
-
-static struct arpc *arpc_find(struct es2_ap_dev *es2, __le16 id)
-{
- struct arpc *rpc;
-
- list_for_each_entry(rpc, &es2->arpcs, list) {
- if (rpc->req->id == id)
- return rpc;
- }
-
- return NULL;
-}
-
-static void arpc_add(struct es2_ap_dev *es2, struct arpc *rpc)
-{
- rpc->active = true;
- rpc->req->id = cpu_to_le16(es2->arpc_id_cycle++);
- list_add_tail(&rpc->list, &es2->arpcs);
-}
-
-static void arpc_del(struct es2_ap_dev *es2, struct arpc *rpc)
-{
- if (rpc->active) {
- rpc->active = false;
- list_del(&rpc->list);
- }
-}
-
-static int arpc_send(struct es2_ap_dev *es2, struct arpc *rpc, int timeout)
-{
- struct usb_device *udev = es2->usb_dev;
- int retval;
-
- retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- GB_APB_REQUEST_ARPC_RUN,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE,
- 0, 0,
- rpc->req, le16_to_cpu(rpc->req->size),
- ES2_USB_CTRL_TIMEOUT);
- if (retval != le16_to_cpu(rpc->req->size)) {
- dev_err(&udev->dev,
- "failed to send ARPC request %d: %d\n",
- rpc->req->type, retval);
- if (retval > 0)
- retval = -EIO;
- return retval;
- }
-
- return 0;
-}
-
-static int arpc_sync(struct es2_ap_dev *es2, u8 type, void *payload,
- size_t size, int *result, unsigned int timeout)
-{
- struct arpc *rpc;
- unsigned long flags;
- int retval;
-
- if (result)
- *result = 0;
-
- rpc = arpc_alloc(payload, size, type);
- if (!rpc)
- return -ENOMEM;
-
- spin_lock_irqsave(&es2->arpc_lock, flags);
- arpc_add(es2, rpc);
- spin_unlock_irqrestore(&es2->arpc_lock, flags);
-
- retval = arpc_send(es2, rpc, timeout);
- if (retval)
- goto out_arpc_del;
-
- retval = wait_for_completion_interruptible_timeout(
- &rpc->response_received,
- msecs_to_jiffies(timeout));
- if (retval <= 0) {
- if (!retval)
- retval = -ETIMEDOUT;
- goto out_arpc_del;
- }
-
- if (rpc->resp->result) {
- retval = -EREMOTEIO;
- if (result)
- *result = rpc->resp->result;
- } else {
- retval = 0;
- }
-
-out_arpc_del:
- spin_lock_irqsave(&es2->arpc_lock, flags);
- arpc_del(es2, rpc);
- spin_unlock_irqrestore(&es2->arpc_lock, flags);
- arpc_free(rpc);
-
- if (retval < 0 && retval != -EREMOTEIO) {
- dev_err(&es2->usb_dev->dev,
- "failed to execute ARPC: %d\n", retval);
- }
-
- return retval;
-}
-
-static void arpc_in_callback(struct urb *urb)
-{
- struct es2_ap_dev *es2 = urb->context;
- struct device *dev = &urb->dev->dev;
- int status = check_urb_status(urb);
- struct arpc *rpc;
- struct arpc_response_message *resp;
- unsigned long flags;
- int retval;
-
- if (status) {
- if ((status == -EAGAIN) || (status == -EPROTO))
- goto exit;
-
- /* The urb is being unlinked */
- if (status == -ENOENT || status == -ESHUTDOWN)
- return;
-
- dev_err(dev, "arpc in-urb error %d (dropped)\n", status);
- return;
- }
-
- if (urb->actual_length < sizeof(*resp)) {
- dev_err(dev, "short aprc response received\n");
- goto exit;
- }
-
- resp = urb->transfer_buffer;
- spin_lock_irqsave(&es2->arpc_lock, flags);
- rpc = arpc_find(es2, resp->id);
- if (!rpc) {
- dev_err(dev, "invalid arpc response id received: %u\n",
- le16_to_cpu(resp->id));
- spin_unlock_irqrestore(&es2->arpc_lock, flags);
- goto exit;
- }
-
- arpc_del(es2, rpc);
- memcpy(rpc->resp, resp, sizeof(*resp));
- complete(&rpc->response_received);
- spin_unlock_irqrestore(&es2->arpc_lock, flags);
-
-exit:
- /* put our urb back in the request pool */
- retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval)
- dev_err(dev, "failed to resubmit arpc in-urb: %d\n", retval);
-}
-
-#define APB1_LOG_MSG_SIZE 64
-static void apb_log_get(struct es2_ap_dev *es2, char *buf)
-{
- int retval;
-
- do {
- retval = usb_control_msg(es2->usb_dev,
- usb_rcvctrlpipe(es2->usb_dev, 0),
- GB_APB_REQUEST_LOG,
- USB_DIR_IN | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE,
- 0x00, 0x00,
- buf,
- APB1_LOG_MSG_SIZE,
- ES2_USB_CTRL_TIMEOUT);
- if (retval > 0)
- kfifo_in(&es2->apb_log_fifo, buf, retval);
- } while (retval > 0);
-}
-
-static int apb_log_poll(void *data)
-{
- struct es2_ap_dev *es2 = data;
- char *buf;
-
- buf = kmalloc(APB1_LOG_MSG_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- while (!kthread_should_stop()) {
- msleep(1000);
- apb_log_get(es2, buf);
- }
-
- kfree(buf);
-
- return 0;
-}
-
-static ssize_t apb_log_read(struct file *f, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct es2_ap_dev *es2 = file_inode(f)->i_private;
- ssize_t ret;
- size_t copied;
- char *tmp_buf;
-
- if (count > APB1_LOG_SIZE)
- count = APB1_LOG_SIZE;
-
- tmp_buf = kmalloc(count, GFP_KERNEL);
- if (!tmp_buf)
- return -ENOMEM;
-
- copied = kfifo_out(&es2->apb_log_fifo, tmp_buf, count);
- ret = simple_read_from_buffer(buf, count, ppos, tmp_buf, copied);
-
- kfree(tmp_buf);
-
- return ret;
-}
-
-static const struct file_operations apb_log_fops = {
- .read = apb_log_read,
-};
-
-static void usb_log_enable(struct es2_ap_dev *es2)
-{
- if (!IS_ERR_OR_NULL(es2->apb_log_task))
- return;
-
- /* get log from APB1 */
- es2->apb_log_task = kthread_run(apb_log_poll, es2, "apb_log");
- if (IS_ERR(es2->apb_log_task))
- return;
- /* XXX We will need to rename this per APB */
- es2->apb_log_dentry = debugfs_create_file("apb_log", 0444,
- gb_debugfs_get(), es2,
- &apb_log_fops);
-}
-
-static void usb_log_disable(struct es2_ap_dev *es2)
-{
- if (IS_ERR_OR_NULL(es2->apb_log_task))
- return;
-
- debugfs_remove(es2->apb_log_dentry);
- es2->apb_log_dentry = NULL;
-
- kthread_stop(es2->apb_log_task);
- es2->apb_log_task = NULL;
-}
-
-static ssize_t apb_log_enable_read(struct file *f, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct es2_ap_dev *es2 = file_inode(f)->i_private;
- int enable = !IS_ERR_OR_NULL(es2->apb_log_task);
- char tmp_buf[3];
-
- sprintf(tmp_buf, "%d\n", enable);
- return simple_read_from_buffer(buf, count, ppos, tmp_buf, 3);
-}
-
-static ssize_t apb_log_enable_write(struct file *f, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- int enable;
- ssize_t retval;
- struct es2_ap_dev *es2 = file_inode(f)->i_private;
-
- retval = kstrtoint_from_user(buf, count, 10, &enable);
- if (retval)
- return retval;
-
- if (enable)
- usb_log_enable(es2);
- else
- usb_log_disable(es2);
-
- return count;
-}
-
-static const struct file_operations apb_log_enable_fops = {
- .read = apb_log_enable_read,
- .write = apb_log_enable_write,
-};
-
-static int apb_get_cport_count(struct usb_device *udev)
-{
- int retval;
- __le16 *cport_count;
-
- cport_count = kzalloc(sizeof(*cport_count), GFP_KERNEL);
- if (!cport_count)
- return -ENOMEM;
-
- retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- GB_APB_REQUEST_CPORT_COUNT,
- USB_DIR_IN | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE, 0, 0, cport_count,
- sizeof(*cport_count), ES2_USB_CTRL_TIMEOUT);
- if (retval != sizeof(*cport_count)) {
- dev_err(&udev->dev, "Cannot retrieve CPort count: %d\n",
- retval);
-
- if (retval >= 0)
- retval = -EIO;
-
- goto out;
- }
-
- retval = le16_to_cpu(*cport_count);
-
- /* We need to fit a CPort ID in one byte of a message header */
- if (retval > U8_MAX) {
- retval = U8_MAX;
- dev_warn(&udev->dev, "Limiting number of CPorts to U8_MAX\n");
- }
-
-out:
- kfree(cport_count);
- return retval;
-}
-
-/*
- * The ES2 USB Bridge device has 15 endpoints
- * 1 Control - usual USB stuff + AP -> APBridgeA messages
- * 7 Bulk IN - CPort data in
- * 7 Bulk OUT - CPort data out
- */
-static int ap_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct es2_ap_dev *es2;
- struct gb_host_device *hd;
- struct usb_device *udev;
- struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
- __u8 ep_addr;
- int retval;
- int i;
- int num_cports;
- bool bulk_out_found = false;
- bool bulk_in_found = false;
- bool arpc_in_found = false;
-
- udev = usb_get_dev(interface_to_usbdev(interface));
-
- num_cports = apb_get_cport_count(udev);
- if (num_cports < 0) {
- usb_put_dev(udev);
- dev_err(&udev->dev, "Cannot retrieve CPort count: %d\n",
- num_cports);
- return num_cports;
- }
-
- hd = gb_hd_create(&es2_driver, &udev->dev, ES2_GBUF_MSG_SIZE_MAX,
- num_cports);
- if (IS_ERR(hd)) {
- usb_put_dev(udev);
- return PTR_ERR(hd);
- }
-
- es2 = hd_to_es2(hd);
- es2->hd = hd;
- es2->usb_intf = interface;
- es2->usb_dev = udev;
- spin_lock_init(&es2->cport_out_urb_lock);
- INIT_KFIFO(es2->apb_log_fifo);
- usb_set_intfdata(interface, es2);
-
- /*
- * Reserve the CDSI0 and CDSI1 CPorts so they won't be allocated
- * dynamically.
- */
- retval = gb_hd_cport_reserve(hd, ES2_CPORT_CDSI0);
- if (retval)
- goto error;
- retval = gb_hd_cport_reserve(hd, ES2_CPORT_CDSI1);
- if (retval)
- goto error;
-
- /* find all bulk endpoints */
- iface_desc = interface->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- ep_addr = endpoint->bEndpointAddress;
-
- if (usb_endpoint_is_bulk_in(endpoint)) {
- if (!bulk_in_found) {
- es2->cport_in.endpoint = ep_addr;
- bulk_in_found = true;
- } else if (!arpc_in_found) {
- es2->arpc_endpoint_in = ep_addr;
- arpc_in_found = true;
- } else {
- dev_warn(&udev->dev,
- "Unused bulk IN endpoint found: 0x%02x\n",
- ep_addr);
- }
- continue;
- }
- if (usb_endpoint_is_bulk_out(endpoint)) {
- if (!bulk_out_found) {
- es2->cport_out_endpoint = ep_addr;
- bulk_out_found = true;
- } else {
- dev_warn(&udev->dev,
- "Unused bulk OUT endpoint found: 0x%02x\n",
- ep_addr);
- }
- continue;
- }
- dev_warn(&udev->dev,
- "Unknown endpoint type found, address 0x%02x\n",
- ep_addr);
- }
- if (!bulk_in_found || !arpc_in_found || !bulk_out_found) {
- dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
- retval = -ENODEV;
- goto error;
- }
-
- /* Allocate buffers for our cport in messages */
- for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
- struct urb *urb;
- u8 *buffer;
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- retval = -ENOMEM;
- goto error;
- }
- es2->cport_in.urb[i] = urb;
-
- buffer = kmalloc(ES2_GBUF_MSG_SIZE_MAX, GFP_KERNEL);
- if (!buffer) {
- retval = -ENOMEM;
- goto error;
- }
-
- usb_fill_bulk_urb(urb, udev,
- usb_rcvbulkpipe(udev, es2->cport_in.endpoint),
- buffer, ES2_GBUF_MSG_SIZE_MAX,
- cport_in_callback, hd);
-
- es2->cport_in.buffer[i] = buffer;
- }
-
- /* Allocate buffers for ARPC in messages */
- for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
- struct urb *urb;
- u8 *buffer;
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- retval = -ENOMEM;
- goto error;
- }
- es2->arpc_urb[i] = urb;
-
- buffer = kmalloc(ARPC_IN_SIZE_MAX, GFP_KERNEL);
- if (!buffer) {
- retval = -ENOMEM;
- goto error;
- }
-
- usb_fill_bulk_urb(urb, udev,
- usb_rcvbulkpipe(udev,
- es2->arpc_endpoint_in),
- buffer, ARPC_IN_SIZE_MAX,
- arpc_in_callback, es2);
-
- es2->arpc_buffer[i] = buffer;
- }
-
- /* Allocate urbs for our CPort OUT messages */
- for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
- struct urb *urb;
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- retval = -ENOMEM;
- goto error;
- }
-
- es2->cport_out_urb[i] = urb;
- es2->cport_out_urb_busy[i] = false; /* just to be anal */
- }
-
- /* XXX We will need to rename this per APB */
- es2->apb_log_enable_dentry = debugfs_create_file("apb_log_enable",
- 0644,
- gb_debugfs_get(), es2,
- &apb_log_enable_fops);
-
- INIT_LIST_HEAD(&es2->arpcs);
- spin_lock_init(&es2->arpc_lock);
-
- retval = es2_arpc_in_enable(es2);
- if (retval)
- goto error;
-
- retval = gb_hd_add(hd);
- if (retval)
- goto err_disable_arpc_in;
-
- retval = es2_cport_in_enable(es2, &es2->cport_in);
- if (retval)
- goto err_hd_del;
-
- return 0;
-
-err_hd_del:
- gb_hd_del(hd);
-err_disable_arpc_in:
- es2_arpc_in_disable(es2);
-error:
- es2_destroy(es2);
-
- return retval;
-}
-
-static void ap_disconnect(struct usb_interface *interface)
-{
- struct es2_ap_dev *es2 = usb_get_intfdata(interface);
-
- gb_hd_del(es2->hd);
-
- es2_cport_in_disable(es2, &es2->cport_in);
- es2_arpc_in_disable(es2);
-
- es2_destroy(es2);
-}
-
-static struct usb_driver es2_ap_driver = {
- .name = "es2_ap_driver",
- .probe = ap_probe,
- .disconnect = ap_disconnect,
- .id_table = id_table,
- .soft_unbind = 1,
-};
-
-module_usb_driver(es2_ap_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
diff --git a/drivers/staging/greybus/firmware.h b/drivers/staging/greybus/firmware.h
index 946221307ef6..5d2564462ffc 100644
--- a/drivers/staging/greybus/firmware.h
+++ b/drivers/staging/greybus/firmware.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Greybus Firmware Management Header
*
@@ -9,7 +9,7 @@
#ifndef __FIRMWARE_H
#define __FIRMWARE_H
-#include "greybus.h"
+#include <linux/greybus.h>
#define FW_NAME_PREFIX "gmp_"
diff --git a/drivers/staging/greybus/fw-core.c b/drivers/staging/greybus/fw-core.c
index 388866d92f5b..57bebf24636b 100644
--- a/drivers/staging/greybus/fw-core.c
+++ b/drivers/staging/greybus/fw-core.c
@@ -8,8 +8,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/firmware.h>
+#include <linux/greybus.h>
#include "firmware.h"
-#include "greybus.h"
#include "spilib.h"
struct gb_fw_core {
diff --git a/drivers/staging/greybus/fw-download.c b/drivers/staging/greybus/fw-download.c
index d3b7cccbc10d..543692c567f9 100644
--- a/drivers/staging/greybus/fw-download.c
+++ b/drivers/staging/greybus/fw-download.c
@@ -10,8 +10,8 @@
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
+#include <linux/greybus.h>
#include "firmware.h"
-#include "greybus.h"
/* Estimated minimum buffer size, actual size can be smaller than this */
#define MIN_FETCH_SIZE 512
diff --git a/drivers/staging/greybus/fw-management.c b/drivers/staging/greybus/fw-management.c
index 71aec14f8181..687c6405c65b 100644
--- a/drivers/staging/greybus/fw-management.c
+++ b/drivers/staging/greybus/fw-management.c
@@ -13,10 +13,10 @@
#include <linux/idr.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
+#include <linux/greybus.h>
#include "firmware.h"
#include "greybus_firmware.h"
-#include "greybus.h"
#define FW_MGMT_TIMEOUT_MS 1000
diff --git a/drivers/staging/greybus/gb-camera.h b/drivers/staging/greybus/gb-camera.h
index ee293e461fc3..5fc469101fc1 100644
--- a/drivers/staging/greybus/gb-camera.h
+++ b/drivers/staging/greybus/gb-camera.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Greybus Camera protocol driver.
*
diff --git a/drivers/staging/greybus/gbphy.c b/drivers/staging/greybus/gbphy.c
index 6cb85c3d3572..9fc5c47be9bd 100644
--- a/drivers/staging/greybus/gbphy.c
+++ b/drivers/staging/greybus/gbphy.c
@@ -13,8 +13,8 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "gbphy.h"
#define GB_GBPHY_AUTOSUSPEND_MS 3000
diff --git a/drivers/staging/greybus/gbphy.h b/drivers/staging/greybus/gbphy.h
index 99463489d7d6..087928a586fb 100644
--- a/drivers/staging/greybus/gbphy.h
+++ b/drivers/staging/greybus/gbphy.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Greybus Bridged-Phy Bus driver
*
diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c
index 3151004d26fb..1ff34abd5692 100644
--- a/drivers/staging/greybus/gpio.c
+++ b/drivers/staging/greybus/gpio.c
@@ -13,8 +13,8 @@
#include <linux/irqdomain.h>
#include <linux/gpio/driver.h>
#include <linux/mutex.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "gbphy.h"
struct gb_gpio_line {
diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h
deleted file mode 100644
index d03ddb7c9df0..000000000000
--- a/drivers/staging/greybus/greybus.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus driver and device API
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- */
-
-#ifndef __LINUX_GREYBUS_H
-#define __LINUX_GREYBUS_H
-
-#ifdef __KERNEL__
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/pm_runtime.h>
-#include <linux/idr.h>
-
-#include "greybus_id.h"
-#include "greybus_manifest.h"
-#include "greybus_protocols.h"
-#include "manifest.h"
-#include "hd.h"
-#include "svc.h"
-#include "control.h"
-#include "module.h"
-#include "interface.h"
-#include "bundle.h"
-#include "connection.h"
-#include "operation.h"
-
-/* Matches up with the Greybus Protocol specification document */
-#define GREYBUS_VERSION_MAJOR 0x00
-#define GREYBUS_VERSION_MINOR 0x01
-
-#define GREYBUS_ID_MATCH_DEVICE \
- (GREYBUS_ID_MATCH_VENDOR | GREYBUS_ID_MATCH_PRODUCT)
-
-#define GREYBUS_DEVICE(v, p) \
- .match_flags = GREYBUS_ID_MATCH_DEVICE, \
- .vendor = (v), \
- .product = (p),
-
-#define GREYBUS_DEVICE_CLASS(c) \
- .match_flags = GREYBUS_ID_MATCH_CLASS, \
- .class = (c),
-
-/* Maximum number of CPorts */
-#define CPORT_ID_MAX 4095 /* UniPro max id is 4095 */
-#define CPORT_ID_BAD U16_MAX
-
-struct greybus_driver {
- const char *name;
-
- int (*probe)(struct gb_bundle *bundle,
- const struct greybus_bundle_id *id);
- void (*disconnect)(struct gb_bundle *bundle);
-
- const struct greybus_bundle_id *id_table;
-
- struct device_driver driver;
-};
-#define to_greybus_driver(d) container_of(d, struct greybus_driver, driver)
-
-static inline void greybus_set_drvdata(struct gb_bundle *bundle, void *data)
-{
- dev_set_drvdata(&bundle->dev, data);
-}
-
-static inline void *greybus_get_drvdata(struct gb_bundle *bundle)
-{
- return dev_get_drvdata(&bundle->dev);
-}
-
-/* Don't call these directly, use the module_greybus_driver() macro instead */
-int greybus_register_driver(struct greybus_driver *driver,
- struct module *module, const char *mod_name);
-void greybus_deregister_driver(struct greybus_driver *driver);
-
-/* define to get proper THIS_MODULE and KBUILD_MODNAME values */
-#define greybus_register(driver) \
- greybus_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
-#define greybus_deregister(driver) \
- greybus_deregister_driver(driver)
-
-/**
- * module_greybus_driver() - Helper macro for registering a Greybus driver
- * @__greybus_driver: greybus_driver structure
- *
- * Helper macro for Greybus drivers to set up proper module init / exit
- * functions. Replaces module_init() and module_exit() and keeps people from
- * printing pointless things to the kernel log when their driver is loaded.
- */
-#define module_greybus_driver(__greybus_driver) \
- module_driver(__greybus_driver, greybus_register, greybus_deregister)
-
-int greybus_disabled(void);
-
-void gb_debugfs_init(void);
-void gb_debugfs_cleanup(void);
-struct dentry *gb_debugfs_get(void);
-
-extern struct bus_type greybus_bus_type;
-
-extern struct device_type greybus_hd_type;
-extern struct device_type greybus_module_type;
-extern struct device_type greybus_interface_type;
-extern struct device_type greybus_control_type;
-extern struct device_type greybus_bundle_type;
-extern struct device_type greybus_svc_type;
-
-static inline int is_gb_host_device(const struct device *dev)
-{
- return dev->type == &greybus_hd_type;
-}
-
-static inline int is_gb_module(const struct device *dev)
-{
- return dev->type == &greybus_module_type;
-}
-
-static inline int is_gb_interface(const struct device *dev)
-{
- return dev->type == &greybus_interface_type;
-}
-
-static inline int is_gb_control(const struct device *dev)
-{
- return dev->type == &greybus_control_type;
-}
-
-static inline int is_gb_bundle(const struct device *dev)
-{
- return dev->type == &greybus_bundle_type;
-}
-
-static inline int is_gb_svc(const struct device *dev)
-{
- return dev->type == &greybus_svc_type;
-}
-
-static inline bool cport_id_valid(struct gb_host_device *hd, u16 cport_id)
-{
- return cport_id != CPORT_ID_BAD && cport_id < hd->num_cports;
-}
-
-#endif /* __KERNEL__ */
-#endif /* __LINUX_GREYBUS_H */
diff --git a/drivers/staging/greybus/greybus_authentication.h b/drivers/staging/greybus/greybus_authentication.h
index 03ea9615b217..7edc7295b7ab 100644
--- a/drivers/staging/greybus/greybus_authentication.h
+++ b/drivers/staging/greybus/greybus_authentication.h
@@ -1,55 +1,9 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* Greybus Component Authentication User Header
*
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
* Copyright(c) 2016 Google Inc. All rights reserved.
* Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 for more details.
- *
- * BSD LICENSE
- *
- * Copyright(c) 2016 Google Inc. All rights reserved.
- * Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
- * its contributors may be used to endorse or promote products
- * derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
- * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __GREYBUS_AUTHENTICATION_USER_H
diff --git a/drivers/staging/greybus/greybus_firmware.h b/drivers/staging/greybus/greybus_firmware.h
index b58281a63ba4..f68fd5e25321 100644
--- a/drivers/staging/greybus/greybus_firmware.h
+++ b/drivers/staging/greybus/greybus_firmware.h
@@ -1,55 +1,9 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* Greybus Firmware Management User Header
*
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
* Copyright(c) 2016 Google Inc. All rights reserved.
* Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 for more details.
- *
- * BSD LICENSE
- *
- * Copyright(c) 2016 Google Inc. All rights reserved.
- * Copyright(c) 2016 Linaro Ltd. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
- * its contributors may be used to endorse or promote products
- * derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
- * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __GREYBUS_FIRMWARE_USER_H
diff --git a/drivers/staging/greybus/greybus_id.h b/drivers/staging/greybus/greybus_id.h
deleted file mode 100644
index f4c8440093e4..000000000000
--- a/drivers/staging/greybus/greybus_id.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* FIXME
- * move this to include/linux/mod_devicetable.h when merging
- */
-
-#ifndef __LINUX_GREYBUS_ID_H
-#define __LINUX_GREYBUS_ID_H
-
-#include <linux/types.h>
-#include <linux/mod_devicetable.h>
-
-
-struct greybus_bundle_id {
- __u16 match_flags;
- __u32 vendor;
- __u32 product;
- __u8 class;
-
- kernel_ulong_t driver_info __aligned(sizeof(kernel_ulong_t));
-};
-
-/* Used to match the greybus_bundle_id */
-#define GREYBUS_ID_MATCH_VENDOR BIT(0)
-#define GREYBUS_ID_MATCH_PRODUCT BIT(1)
-#define GREYBUS_ID_MATCH_CLASS BIT(2)
-
-#endif /* __LINUX_GREYBUS_ID_H */
diff --git a/drivers/staging/greybus/greybus_manifest.h b/drivers/staging/greybus/greybus_manifest.h
deleted file mode 100644
index 2cec5cf7a846..000000000000
--- a/drivers/staging/greybus/greybus_manifest.h
+++ /dev/null
@@ -1,178 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus manifest definition
- *
- * See "Greybus Application Protocol" document (version 0.1) for
- * details on these values and structures.
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- *
- * Released under the GPLv2 and BSD licenses.
- */
-
-#ifndef __GREYBUS_MANIFEST_H
-#define __GREYBUS_MANIFEST_H
-
-enum greybus_descriptor_type {
- GREYBUS_TYPE_INVALID = 0x00,
- GREYBUS_TYPE_INTERFACE = 0x01,
- GREYBUS_TYPE_STRING = 0x02,
- GREYBUS_TYPE_BUNDLE = 0x03,
- GREYBUS_TYPE_CPORT = 0x04,
-};
-
-enum greybus_protocol {
- GREYBUS_PROTOCOL_CONTROL = 0x00,
- /* 0x01 is unused */
- GREYBUS_PROTOCOL_GPIO = 0x02,
- GREYBUS_PROTOCOL_I2C = 0x03,
- GREYBUS_PROTOCOL_UART = 0x04,
- GREYBUS_PROTOCOL_HID = 0x05,
- GREYBUS_PROTOCOL_USB = 0x06,
- GREYBUS_PROTOCOL_SDIO = 0x07,
- GREYBUS_PROTOCOL_POWER_SUPPLY = 0x08,
- GREYBUS_PROTOCOL_PWM = 0x09,
- /* 0x0a is unused */
- GREYBUS_PROTOCOL_SPI = 0x0b,
- GREYBUS_PROTOCOL_DISPLAY = 0x0c,
- GREYBUS_PROTOCOL_CAMERA_MGMT = 0x0d,
- GREYBUS_PROTOCOL_SENSOR = 0x0e,
- GREYBUS_PROTOCOL_LIGHTS = 0x0f,
- GREYBUS_PROTOCOL_VIBRATOR = 0x10,
- GREYBUS_PROTOCOL_LOOPBACK = 0x11,
- GREYBUS_PROTOCOL_AUDIO_MGMT = 0x12,
- GREYBUS_PROTOCOL_AUDIO_DATA = 0x13,
- GREYBUS_PROTOCOL_SVC = 0x14,
- GREYBUS_PROTOCOL_BOOTROM = 0x15,
- GREYBUS_PROTOCOL_CAMERA_DATA = 0x16,
- GREYBUS_PROTOCOL_FW_DOWNLOAD = 0x17,
- GREYBUS_PROTOCOL_FW_MANAGEMENT = 0x18,
- GREYBUS_PROTOCOL_AUTHENTICATION = 0x19,
- GREYBUS_PROTOCOL_LOG = 0x1a,
- /* ... */
- GREYBUS_PROTOCOL_RAW = 0xfe,
- GREYBUS_PROTOCOL_VENDOR = 0xff,
-};
-
-enum greybus_class_type {
- GREYBUS_CLASS_CONTROL = 0x00,
- /* 0x01 is unused */
- /* 0x02 is unused */
- /* 0x03 is unused */
- /* 0x04 is unused */
- GREYBUS_CLASS_HID = 0x05,
- /* 0x06 is unused */
- /* 0x07 is unused */
- GREYBUS_CLASS_POWER_SUPPLY = 0x08,
- /* 0x09 is unused */
- GREYBUS_CLASS_BRIDGED_PHY = 0x0a,
- /* 0x0b is unused */
- GREYBUS_CLASS_DISPLAY = 0x0c,
- GREYBUS_CLASS_CAMERA = 0x0d,
- GREYBUS_CLASS_SENSOR = 0x0e,
- GREYBUS_CLASS_LIGHTS = 0x0f,
- GREYBUS_CLASS_VIBRATOR = 0x10,
- GREYBUS_CLASS_LOOPBACK = 0x11,
- GREYBUS_CLASS_AUDIO = 0x12,
- /* 0x13 is unused */
- /* 0x14 is unused */
- GREYBUS_CLASS_BOOTROM = 0x15,
- GREYBUS_CLASS_FW_MANAGEMENT = 0x16,
- GREYBUS_CLASS_LOG = 0x17,
- /* ... */
- GREYBUS_CLASS_RAW = 0xfe,
- GREYBUS_CLASS_VENDOR = 0xff,
-};
-
-enum {
- GREYBUS_INTERFACE_FEATURE_TIMESYNC = BIT(0),
-};
-
-/*
- * The string in a string descriptor is not NUL-terminated. The
- * size of the descriptor will be rounded up to a multiple of 4
- * bytes, by padding the string with 0x00 bytes if necessary.
- */
-struct greybus_descriptor_string {
- __u8 length;
- __u8 id;
- __u8 string[0];
-} __packed;
-
-/*
- * An interface descriptor describes information about an interface as a whole,
- * *not* the functions within it.
- */
-struct greybus_descriptor_interface {
- __u8 vendor_stringid;
- __u8 product_stringid;
- __u8 features;
- __u8 pad;
-} __packed;
-
-/*
- * An bundle descriptor defines an identification number and a class for
- * each bundle.
- *
- * @id: Uniquely identifies a bundle within a interface, its sole purpose is to
- * allow CPort descriptors to specify which bundle they are associated with.
- * The first bundle will have id 0, second will have 1 and so on.
- *
- * The largest CPort id associated with an bundle (defined by a
- * CPort descriptor in the manifest) is used to determine how to
- * encode the device id and module number in UniPro packets
- * that use the bundle.
- *
- * @class: It is used by kernel to know the functionality provided by the
- * bundle and will be matched against drivers functinality while probing greybus
- * driver. It should contain one of the values defined in
- * 'enum greybus_class_type'.
- *
- */
-struct greybus_descriptor_bundle {
- __u8 id; /* interface-relative id (0..) */
- __u8 class;
- __u8 pad[2];
-} __packed;
-
-/*
- * A CPort descriptor indicates the id of the bundle within the
- * module it's associated with, along with the CPort id used to
- * address the CPort. The protocol id defines the format of messages
- * exchanged using the CPort.
- */
-struct greybus_descriptor_cport {
- __le16 id;
- __u8 bundle;
- __u8 protocol_id; /* enum greybus_protocol */
-} __packed;
-
-struct greybus_descriptor_header {
- __le16 size;
- __u8 type; /* enum greybus_descriptor_type */
- __u8 pad;
-} __packed;
-
-struct greybus_descriptor {
- struct greybus_descriptor_header header;
- union {
- struct greybus_descriptor_string string;
- struct greybus_descriptor_interface interface;
- struct greybus_descriptor_bundle bundle;
- struct greybus_descriptor_cport cport;
- };
-} __packed;
-
-struct greybus_manifest_header {
- __le16 size;
- __u8 version_major;
- __u8 version_minor;
-} __packed;
-
-struct greybus_manifest {
- struct greybus_manifest_header header;
- struct greybus_descriptor descriptors[0];
-} __packed;
-
-#endif /* __GREYBUS_MANIFEST_H */
diff --git a/drivers/staging/greybus/greybus_protocols.h b/drivers/staging/greybus/greybus_protocols.h
deleted file mode 100644
index ddc73f10eb22..000000000000
--- a/drivers/staging/greybus/greybus_protocols.h
+++ /dev/null
@@ -1,2222 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
-/*
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2014 - 2015 Google Inc. All rights reserved.
- * Copyright(c) 2014 - 2015 Linaro Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 for more details.
- *
- * BSD LICENSE
- *
- * Copyright(c) 2014 - 2015 Google Inc. All rights reserved.
- * Copyright(c) 2014 - 2015 Linaro Ltd. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
- * its contributors may be used to endorse or promote products
- * derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
- * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __GREYBUS_PROTOCOLS_H
-#define __GREYBUS_PROTOCOLS_H
-
-/* Fixed IDs for control/svc protocols */
-
-/* SVC switch-port device ids */
-#define GB_SVC_DEVICE_ID_SVC 0
-#define GB_SVC_DEVICE_ID_AP 1
-#define GB_SVC_DEVICE_ID_MIN 2
-#define GB_SVC_DEVICE_ID_MAX 31
-
-#define GB_SVC_CPORT_ID 0
-#define GB_CONTROL_BUNDLE_ID 0
-#define GB_CONTROL_CPORT_ID 0
-
-
-/*
- * All operation messages (both requests and responses) begin with
- * a header that encodes the size of the message (header included).
- * This header also contains a unique identifier, that associates a
- * response message with its operation. The header contains an
- * operation type field, whose interpretation is dependent on what
- * type of protocol is used over the connection. The high bit
- * (0x80) of the operation type field is used to indicate whether
- * the message is a request (clear) or a response (set).
- *
- * Response messages include an additional result byte, which
- * communicates the result of the corresponding request. A zero
- * result value means the operation completed successfully. Any
- * other value indicates an error; in this case, the payload of the
- * response message (if any) is ignored. The result byte must be
- * zero in the header for a request message.
- *
- * The wire format for all numeric fields in the header is little
- * endian. Any operation-specific data begins immediately after the
- * header.
- */
-struct gb_operation_msg_hdr {
- __le16 size; /* Size in bytes of header + payload */
- __le16 operation_id; /* Operation unique id */
- __u8 type; /* E.g GB_I2C_TYPE_* or GB_GPIO_TYPE_* */
- __u8 result; /* Result of request (in responses only) */
- __u8 pad[2]; /* must be zero (ignore when read) */
-} __packed;
-
-
-/* Generic request types */
-#define GB_REQUEST_TYPE_CPORT_SHUTDOWN 0x00
-#define GB_REQUEST_TYPE_INVALID 0x7f
-
-struct gb_cport_shutdown_request {
- __u8 phase;
-} __packed;
-
-
-/* Control Protocol */
-
-/* Greybus control request types */
-#define GB_CONTROL_TYPE_VERSION 0x01
-#define GB_CONTROL_TYPE_PROBE_AP 0x02
-#define GB_CONTROL_TYPE_GET_MANIFEST_SIZE 0x03
-#define GB_CONTROL_TYPE_GET_MANIFEST 0x04
-#define GB_CONTROL_TYPE_CONNECTED 0x05
-#define GB_CONTROL_TYPE_DISCONNECTED 0x06
-#define GB_CONTROL_TYPE_TIMESYNC_ENABLE 0x07
-#define GB_CONTROL_TYPE_TIMESYNC_DISABLE 0x08
-#define GB_CONTROL_TYPE_TIMESYNC_AUTHORITATIVE 0x09
-/* Unused 0x0a */
-#define GB_CONTROL_TYPE_BUNDLE_VERSION 0x0b
-#define GB_CONTROL_TYPE_DISCONNECTING 0x0c
-#define GB_CONTROL_TYPE_TIMESYNC_GET_LAST_EVENT 0x0d
-#define GB_CONTROL_TYPE_MODE_SWITCH 0x0e
-#define GB_CONTROL_TYPE_BUNDLE_SUSPEND 0x0f
-#define GB_CONTROL_TYPE_BUNDLE_RESUME 0x10
-#define GB_CONTROL_TYPE_BUNDLE_DEACTIVATE 0x11
-#define GB_CONTROL_TYPE_BUNDLE_ACTIVATE 0x12
-#define GB_CONTROL_TYPE_INTF_SUSPEND_PREPARE 0x13
-#define GB_CONTROL_TYPE_INTF_DEACTIVATE_PREPARE 0x14
-#define GB_CONTROL_TYPE_INTF_HIBERNATE_ABORT 0x15
-
-struct gb_control_version_request {
- __u8 major;
- __u8 minor;
-} __packed;
-
-struct gb_control_version_response {
- __u8 major;
- __u8 minor;
-} __packed;
-
-struct gb_control_bundle_version_request {
- __u8 bundle_id;
-} __packed;
-
-struct gb_control_bundle_version_response {
- __u8 major;
- __u8 minor;
-} __packed;
-
-/* Control protocol manifest get size request has no payload*/
-struct gb_control_get_manifest_size_response {
- __le16 size;
-} __packed;
-
-/* Control protocol manifest get request has no payload */
-struct gb_control_get_manifest_response {
- __u8 data[0];
-} __packed;
-
-/* Control protocol [dis]connected request */
-struct gb_control_connected_request {
- __le16 cport_id;
-} __packed;
-
-struct gb_control_disconnecting_request {
- __le16 cport_id;
-} __packed;
-/* disconnecting response has no payload */
-
-struct gb_control_disconnected_request {
- __le16 cport_id;
-} __packed;
-/* Control protocol [dis]connected response has no payload */
-
-/*
- * All Bundle power management operations use the same request and response
- * layout and status codes.
- */
-
-#define GB_CONTROL_BUNDLE_PM_OK 0x00
-#define GB_CONTROL_BUNDLE_PM_INVAL 0x01
-#define GB_CONTROL_BUNDLE_PM_BUSY 0x02
-#define GB_CONTROL_BUNDLE_PM_FAIL 0x03
-#define GB_CONTROL_BUNDLE_PM_NA 0x04
-
-struct gb_control_bundle_pm_request {
- __u8 bundle_id;
-} __packed;
-
-struct gb_control_bundle_pm_response {
- __u8 status;
-} __packed;
-
-/*
- * Interface Suspend Prepare and Deactivate Prepare operations use the same
- * response layout and error codes. Define a single response structure and reuse
- * it. Both operations have no payload.
- */
-
-#define GB_CONTROL_INTF_PM_OK 0x00
-#define GB_CONTROL_INTF_PM_BUSY 0x01
-#define GB_CONTROL_INTF_PM_NA 0x02
-
-struct gb_control_intf_pm_response {
- __u8 status;
-} __packed;
-
-/* APBridge protocol */
-
-/* request APB1 log */
-#define GB_APB_REQUEST_LOG 0x02
-
-/* request to map a cport to bulk in and bulk out endpoints */
-#define GB_APB_REQUEST_EP_MAPPING 0x03
-
-/* request to get the number of cports available */
-#define GB_APB_REQUEST_CPORT_COUNT 0x04
-
-/* request to reset a cport state */
-#define GB_APB_REQUEST_RESET_CPORT 0x05
-
-/* request to time the latency of messages on a given cport */
-#define GB_APB_REQUEST_LATENCY_TAG_EN 0x06
-#define GB_APB_REQUEST_LATENCY_TAG_DIS 0x07
-
-/* request to control the CSI transmitter */
-#define GB_APB_REQUEST_CSI_TX_CONTROL 0x08
-
-/* request to control audio streaming */
-#define GB_APB_REQUEST_AUDIO_CONTROL 0x09
-
-/* TimeSync requests */
-#define GB_APB_REQUEST_TIMESYNC_ENABLE 0x0d
-#define GB_APB_REQUEST_TIMESYNC_DISABLE 0x0e
-#define GB_APB_REQUEST_TIMESYNC_AUTHORITATIVE 0x0f
-#define GB_APB_REQUEST_TIMESYNC_GET_LAST_EVENT 0x10
-
-/* requests to set Greybus CPort flags */
-#define GB_APB_REQUEST_CPORT_FLAGS 0x11
-
-/* ARPC request */
-#define GB_APB_REQUEST_ARPC_RUN 0x12
-
-struct gb_apb_request_cport_flags {
- __le32 flags;
-#define GB_APB_CPORT_FLAG_CONTROL 0x01
-#define GB_APB_CPORT_FLAG_HIGH_PRIO 0x02
-} __packed;
-
-
-/* Firmware Download Protocol */
-
-/* Request Types */
-#define GB_FW_DOWNLOAD_TYPE_FIND_FIRMWARE 0x01
-#define GB_FW_DOWNLOAD_TYPE_FETCH_FIRMWARE 0x02
-#define GB_FW_DOWNLOAD_TYPE_RELEASE_FIRMWARE 0x03
-
-#define GB_FIRMWARE_TAG_MAX_SIZE 10
-
-/* firmware download find firmware request/response */
-struct gb_fw_download_find_firmware_request {
- __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
-} __packed;
-
-struct gb_fw_download_find_firmware_response {
- __u8 firmware_id;
- __le32 size;
-} __packed;
-
-/* firmware download fetch firmware request/response */
-struct gb_fw_download_fetch_firmware_request {
- __u8 firmware_id;
- __le32 offset;
- __le32 size;
-} __packed;
-
-struct gb_fw_download_fetch_firmware_response {
- __u8 data[0];
-} __packed;
-
-/* firmware download release firmware request */
-struct gb_fw_download_release_firmware_request {
- __u8 firmware_id;
-} __packed;
-/* firmware download release firmware response has no payload */
-
-
-/* Firmware Management Protocol */
-
-/* Request Types */
-#define GB_FW_MGMT_TYPE_INTERFACE_FW_VERSION 0x01
-#define GB_FW_MGMT_TYPE_LOAD_AND_VALIDATE_FW 0x02
-#define GB_FW_MGMT_TYPE_LOADED_FW 0x03
-#define GB_FW_MGMT_TYPE_BACKEND_FW_VERSION 0x04
-#define GB_FW_MGMT_TYPE_BACKEND_FW_UPDATE 0x05
-#define GB_FW_MGMT_TYPE_BACKEND_FW_UPDATED 0x06
-
-#define GB_FW_LOAD_METHOD_UNIPRO 0x01
-#define GB_FW_LOAD_METHOD_INTERNAL 0x02
-
-#define GB_FW_LOAD_STATUS_FAILED 0x00
-#define GB_FW_LOAD_STATUS_UNVALIDATED 0x01
-#define GB_FW_LOAD_STATUS_VALIDATED 0x02
-#define GB_FW_LOAD_STATUS_VALIDATION_FAILED 0x03
-
-#define GB_FW_BACKEND_FW_STATUS_SUCCESS 0x01
-#define GB_FW_BACKEND_FW_STATUS_FAIL_FIND 0x02
-#define GB_FW_BACKEND_FW_STATUS_FAIL_FETCH 0x03
-#define GB_FW_BACKEND_FW_STATUS_FAIL_WRITE 0x04
-#define GB_FW_BACKEND_FW_STATUS_INT 0x05
-#define GB_FW_BACKEND_FW_STATUS_RETRY 0x06
-#define GB_FW_BACKEND_FW_STATUS_NOT_SUPPORTED 0x07
-
-#define GB_FW_BACKEND_VERSION_STATUS_SUCCESS 0x01
-#define GB_FW_BACKEND_VERSION_STATUS_NOT_AVAILABLE 0x02
-#define GB_FW_BACKEND_VERSION_STATUS_NOT_SUPPORTED 0x03
-#define GB_FW_BACKEND_VERSION_STATUS_RETRY 0x04
-#define GB_FW_BACKEND_VERSION_STATUS_FAIL_INT 0x05
-
-/* firmware management interface firmware version request has no payload */
-struct gb_fw_mgmt_interface_fw_version_response {
- __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
- __le16 major;
- __le16 minor;
-} __packed;
-
-/* firmware management load and validate firmware request/response */
-struct gb_fw_mgmt_load_and_validate_fw_request {
- __u8 request_id;
- __u8 load_method;
- __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
-} __packed;
-/* firmware management load and validate firmware response has no payload*/
-
-/* firmware management loaded firmware request */
-struct gb_fw_mgmt_loaded_fw_request {
- __u8 request_id;
- __u8 status;
- __le16 major;
- __le16 minor;
-} __packed;
-/* firmware management loaded firmware response has no payload */
-
-/* firmware management backend firmware version request/response */
-struct gb_fw_mgmt_backend_fw_version_request {
- __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
-} __packed;
-
-struct gb_fw_mgmt_backend_fw_version_response {
- __le16 major;
- __le16 minor;
- __u8 status;
-} __packed;
-
-/* firmware management backend firmware update request */
-struct gb_fw_mgmt_backend_fw_update_request {
- __u8 request_id;
- __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
-} __packed;
-/* firmware management backend firmware update response has no payload */
-
-/* firmware management backend firmware updated request */
-struct gb_fw_mgmt_backend_fw_updated_request {
- __u8 request_id;
- __u8 status;
-} __packed;
-/* firmware management backend firmware updated response has no payload */
-
-
-/* Component Authentication Protocol (CAP) */
-
-/* Request Types */
-#define GB_CAP_TYPE_GET_ENDPOINT_UID 0x01
-#define GB_CAP_TYPE_GET_IMS_CERTIFICATE 0x02
-#define GB_CAP_TYPE_AUTHENTICATE 0x03
-
-/* CAP get endpoint uid request has no payload */
-struct gb_cap_get_endpoint_uid_response {
- __u8 uid[8];
-} __packed;
-
-/* CAP get endpoint ims certificate request/response */
-struct gb_cap_get_ims_certificate_request {
- __le32 certificate_class;
- __le32 certificate_id;
-} __packed;
-
-struct gb_cap_get_ims_certificate_response {
- __u8 result_code;
- __u8 certificate[0];
-} __packed;
-
-/* CAP authenticate request/response */
-struct gb_cap_authenticate_request {
- __le32 auth_type;
- __u8 uid[8];
- __u8 challenge[32];
-} __packed;
-
-struct gb_cap_authenticate_response {
- __u8 result_code;
- __u8 response[64];
- __u8 signature[0];
-} __packed;
-
-
-/* Bootrom Protocol */
-
-/* Version of the Greybus bootrom protocol we support */
-#define GB_BOOTROM_VERSION_MAJOR 0x00
-#define GB_BOOTROM_VERSION_MINOR 0x01
-
-/* Greybus bootrom request types */
-#define GB_BOOTROM_TYPE_VERSION 0x01
-#define GB_BOOTROM_TYPE_FIRMWARE_SIZE 0x02
-#define GB_BOOTROM_TYPE_GET_FIRMWARE 0x03
-#define GB_BOOTROM_TYPE_READY_TO_BOOT 0x04
-#define GB_BOOTROM_TYPE_AP_READY 0x05 /* Request with no-payload */
-#define GB_BOOTROM_TYPE_GET_VID_PID 0x06 /* Request with no-payload */
-
-/* Greybus bootrom boot stages */
-#define GB_BOOTROM_BOOT_STAGE_ONE 0x01 /* Reserved for the boot ROM */
-#define GB_BOOTROM_BOOT_STAGE_TWO 0x02 /* Bootrom package to be loaded by the boot ROM */
-#define GB_BOOTROM_BOOT_STAGE_THREE 0x03 /* Module personality package loaded by Stage 2 firmware */
-
-/* Greybus bootrom ready to boot status */
-#define GB_BOOTROM_BOOT_STATUS_INVALID 0x00 /* Firmware blob could not be validated */
-#define GB_BOOTROM_BOOT_STATUS_INSECURE 0x01 /* Firmware blob is valid but insecure */
-#define GB_BOOTROM_BOOT_STATUS_SECURE 0x02 /* Firmware blob is valid and secure */
-
-/* Max bootrom data fetch size in bytes */
-#define GB_BOOTROM_FETCH_MAX 2000
-
-struct gb_bootrom_version_request {
- __u8 major;
- __u8 minor;
-} __packed;
-
-struct gb_bootrom_version_response {
- __u8 major;
- __u8 minor;
-} __packed;
-
-/* Bootrom protocol firmware size request/response */
-struct gb_bootrom_firmware_size_request {
- __u8 stage;
-} __packed;
-
-struct gb_bootrom_firmware_size_response {
- __le32 size;
-} __packed;
-
-/* Bootrom protocol get firmware request/response */
-struct gb_bootrom_get_firmware_request {
- __le32 offset;
- __le32 size;
-} __packed;
-
-struct gb_bootrom_get_firmware_response {
- __u8 data[0];
-} __packed;
-
-/* Bootrom protocol Ready to boot request */
-struct gb_bootrom_ready_to_boot_request {
- __u8 status;
-} __packed;
-/* Bootrom protocol Ready to boot response has no payload */
-
-/* Bootrom protocol get VID/PID request has no payload */
-struct gb_bootrom_get_vid_pid_response {
- __le32 vendor_id;
- __le32 product_id;
-} __packed;
-
-
-/* Power Supply */
-
-/* Greybus power supply request types */
-#define GB_POWER_SUPPLY_TYPE_GET_SUPPLIES 0x02
-#define GB_POWER_SUPPLY_TYPE_GET_DESCRIPTION 0x03
-#define GB_POWER_SUPPLY_TYPE_GET_PROP_DESCRIPTORS 0x04
-#define GB_POWER_SUPPLY_TYPE_GET_PROPERTY 0x05
-#define GB_POWER_SUPPLY_TYPE_SET_PROPERTY 0x06
-#define GB_POWER_SUPPLY_TYPE_EVENT 0x07
-
-/* Greybus power supply battery technologies types */
-#define GB_POWER_SUPPLY_TECH_UNKNOWN 0x0000
-#define GB_POWER_SUPPLY_TECH_NiMH 0x0001
-#define GB_POWER_SUPPLY_TECH_LION 0x0002
-#define GB_POWER_SUPPLY_TECH_LIPO 0x0003
-#define GB_POWER_SUPPLY_TECH_LiFe 0x0004
-#define GB_POWER_SUPPLY_TECH_NiCd 0x0005
-#define GB_POWER_SUPPLY_TECH_LiMn 0x0006
-
-/* Greybus power supply types */
-#define GB_POWER_SUPPLY_UNKNOWN_TYPE 0x0000
-#define GB_POWER_SUPPLY_BATTERY_TYPE 0x0001
-#define GB_POWER_SUPPLY_UPS_TYPE 0x0002
-#define GB_POWER_SUPPLY_MAINS_TYPE 0x0003
-#define GB_POWER_SUPPLY_USB_TYPE 0x0004
-#define GB_POWER_SUPPLY_USB_DCP_TYPE 0x0005
-#define GB_POWER_SUPPLY_USB_CDP_TYPE 0x0006
-#define GB_POWER_SUPPLY_USB_ACA_TYPE 0x0007
-
-/* Greybus power supply health values */
-#define GB_POWER_SUPPLY_HEALTH_UNKNOWN 0x0000
-#define GB_POWER_SUPPLY_HEALTH_GOOD 0x0001
-#define GB_POWER_SUPPLY_HEALTH_OVERHEAT 0x0002
-#define GB_POWER_SUPPLY_HEALTH_DEAD 0x0003
-#define GB_POWER_SUPPLY_HEALTH_OVERVOLTAGE 0x0004
-#define GB_POWER_SUPPLY_HEALTH_UNSPEC_FAILURE 0x0005
-#define GB_POWER_SUPPLY_HEALTH_COLD 0x0006
-#define GB_POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE 0x0007
-#define GB_POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE 0x0008
-
-/* Greybus power supply status values */
-#define GB_POWER_SUPPLY_STATUS_UNKNOWN 0x0000
-#define GB_POWER_SUPPLY_STATUS_CHARGING 0x0001
-#define GB_POWER_SUPPLY_STATUS_DISCHARGING 0x0002
-#define GB_POWER_SUPPLY_STATUS_NOT_CHARGING 0x0003
-#define GB_POWER_SUPPLY_STATUS_FULL 0x0004
-
-/* Greybus power supply capacity level values */
-#define GB_POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN 0x0000
-#define GB_POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL 0x0001
-#define GB_POWER_SUPPLY_CAPACITY_LEVEL_LOW 0x0002
-#define GB_POWER_SUPPLY_CAPACITY_LEVEL_NORMAL 0x0003
-#define GB_POWER_SUPPLY_CAPACITY_LEVEL_HIGH 0x0004
-#define GB_POWER_SUPPLY_CAPACITY_LEVEL_FULL 0x0005
-
-/* Greybus power supply scope values */
-#define GB_POWER_SUPPLY_SCOPE_UNKNOWN 0x0000
-#define GB_POWER_SUPPLY_SCOPE_SYSTEM 0x0001
-#define GB_POWER_SUPPLY_SCOPE_DEVICE 0x0002
-
-struct gb_power_supply_get_supplies_response {
- __u8 supplies_count;
-} __packed;
-
-struct gb_power_supply_get_description_request {
- __u8 psy_id;
-} __packed;
-
-struct gb_power_supply_get_description_response {
- __u8 manufacturer[32];
- __u8 model[32];
- __u8 serial_number[32];
- __le16 type;
- __u8 properties_count;
-} __packed;
-
-struct gb_power_supply_props_desc {
- __u8 property;
-#define GB_POWER_SUPPLY_PROP_STATUS 0x00
-#define GB_POWER_SUPPLY_PROP_CHARGE_TYPE 0x01
-#define GB_POWER_SUPPLY_PROP_HEALTH 0x02
-#define GB_POWER_SUPPLY_PROP_PRESENT 0x03
-#define GB_POWER_SUPPLY_PROP_ONLINE 0x04
-#define GB_POWER_SUPPLY_PROP_AUTHENTIC 0x05
-#define GB_POWER_SUPPLY_PROP_TECHNOLOGY 0x06
-#define GB_POWER_SUPPLY_PROP_CYCLE_COUNT 0x07
-#define GB_POWER_SUPPLY_PROP_VOLTAGE_MAX 0x08
-#define GB_POWER_SUPPLY_PROP_VOLTAGE_MIN 0x09
-#define GB_POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN 0x0A
-#define GB_POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN 0x0B
-#define GB_POWER_SUPPLY_PROP_VOLTAGE_NOW 0x0C
-#define GB_POWER_SUPPLY_PROP_VOLTAGE_AVG 0x0D
-#define GB_POWER_SUPPLY_PROP_VOLTAGE_OCV 0x0E
-#define GB_POWER_SUPPLY_PROP_VOLTAGE_BOOT 0x0F
-#define GB_POWER_SUPPLY_PROP_CURRENT_MAX 0x10
-#define GB_POWER_SUPPLY_PROP_CURRENT_NOW 0x11
-#define GB_POWER_SUPPLY_PROP_CURRENT_AVG 0x12
-#define GB_POWER_SUPPLY_PROP_CURRENT_BOOT 0x13
-#define GB_POWER_SUPPLY_PROP_POWER_NOW 0x14
-#define GB_POWER_SUPPLY_PROP_POWER_AVG 0x15
-#define GB_POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN 0x16
-#define GB_POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN 0x17
-#define GB_POWER_SUPPLY_PROP_CHARGE_FULL 0x18
-#define GB_POWER_SUPPLY_PROP_CHARGE_EMPTY 0x19
-#define GB_POWER_SUPPLY_PROP_CHARGE_NOW 0x1A
-#define GB_POWER_SUPPLY_PROP_CHARGE_AVG 0x1B
-#define GB_POWER_SUPPLY_PROP_CHARGE_COUNTER 0x1C
-#define GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT 0x1D
-#define GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX 0x1E
-#define GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE 0x1F
-#define GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX 0x20
-#define GB_POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT 0x21
-#define GB_POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX 0x22
-#define GB_POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT 0x23
-#define GB_POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN 0x24
-#define GB_POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN 0x25
-#define GB_POWER_SUPPLY_PROP_ENERGY_FULL 0x26
-#define GB_POWER_SUPPLY_PROP_ENERGY_EMPTY 0x27
-#define GB_POWER_SUPPLY_PROP_ENERGY_NOW 0x28
-#define GB_POWER_SUPPLY_PROP_ENERGY_AVG 0x29
-#define GB_POWER_SUPPLY_PROP_CAPACITY 0x2A
-#define GB_POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN 0x2B
-#define GB_POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX 0x2C
-#define GB_POWER_SUPPLY_PROP_CAPACITY_LEVEL 0x2D
-#define GB_POWER_SUPPLY_PROP_TEMP 0x2E
-#define GB_POWER_SUPPLY_PROP_TEMP_MAX 0x2F
-#define GB_POWER_SUPPLY_PROP_TEMP_MIN 0x30
-#define GB_POWER_SUPPLY_PROP_TEMP_ALERT_MIN 0x31
-#define GB_POWER_SUPPLY_PROP_TEMP_ALERT_MAX 0x32
-#define GB_POWER_SUPPLY_PROP_TEMP_AMBIENT 0x33
-#define GB_POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN 0x34
-#define GB_POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX 0x35
-#define GB_POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW 0x36
-#define GB_POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG 0x37
-#define GB_POWER_SUPPLY_PROP_TIME_TO_FULL_NOW 0x38
-#define GB_POWER_SUPPLY_PROP_TIME_TO_FULL_AVG 0x39
-#define GB_POWER_SUPPLY_PROP_TYPE 0x3A
-#define GB_POWER_SUPPLY_PROP_SCOPE 0x3B
-#define GB_POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT 0x3C
-#define GB_POWER_SUPPLY_PROP_CALIBRATE 0x3D
- __u8 is_writeable;
-} __packed;
-
-struct gb_power_supply_get_property_descriptors_request {
- __u8 psy_id;
-} __packed;
-
-struct gb_power_supply_get_property_descriptors_response {
- __u8 properties_count;
- struct gb_power_supply_props_desc props[];
-} __packed;
-
-struct gb_power_supply_get_property_request {
- __u8 psy_id;
- __u8 property;
-} __packed;
-
-struct gb_power_supply_get_property_response {
- __le32 prop_val;
-};
-
-struct gb_power_supply_set_property_request {
- __u8 psy_id;
- __u8 property;
- __le32 prop_val;
-} __packed;
-
-struct gb_power_supply_event_request {
- __u8 psy_id;
- __u8 event;
-#define GB_POWER_SUPPLY_UPDATE 0x01
-} __packed;
-
-
-/* HID */
-
-/* Greybus HID operation types */
-#define GB_HID_TYPE_GET_DESC 0x02
-#define GB_HID_TYPE_GET_REPORT_DESC 0x03
-#define GB_HID_TYPE_PWR_ON 0x04
-#define GB_HID_TYPE_PWR_OFF 0x05
-#define GB_HID_TYPE_GET_REPORT 0x06
-#define GB_HID_TYPE_SET_REPORT 0x07
-#define GB_HID_TYPE_IRQ_EVENT 0x08
-
-/* Report type */
-#define GB_HID_INPUT_REPORT 0
-#define GB_HID_OUTPUT_REPORT 1
-#define GB_HID_FEATURE_REPORT 2
-
-/* Different request/response structures */
-/* HID get descriptor response */
-struct gb_hid_desc_response {
- __u8 bLength;
- __le16 wReportDescLength;
- __le16 bcdHID;
- __le16 wProductID;
- __le16 wVendorID;
- __u8 bCountryCode;
-} __packed;
-
-/* HID get report request/response */
-struct gb_hid_get_report_request {
- __u8 report_type;
- __u8 report_id;
-} __packed;
-
-/* HID set report request */
-struct gb_hid_set_report_request {
- __u8 report_type;
- __u8 report_id;
- __u8 report[0];
-} __packed;
-
-/* HID input report request, via interrupt pipe */
-struct gb_hid_input_report_request {
- __u8 report[0];
-} __packed;
-
-
-/* I2C */
-
-/* Greybus i2c request types */
-#define GB_I2C_TYPE_FUNCTIONALITY 0x02
-#define GB_I2C_TYPE_TRANSFER 0x05
-
-/* functionality request has no payload */
-struct gb_i2c_functionality_response {
- __le32 functionality;
-} __packed;
-
-/*
- * Outgoing data immediately follows the op count and ops array.
- * The data for each write (master -> slave) op in the array is sent
- * in order, with no (e.g. pad) bytes separating them.
- *
- * Short reads cause the entire transfer request to fail So response
- * payload consists only of bytes read, and the number of bytes is
- * exactly what was specified in the corresponding op. Like
- * outgoing data, the incoming data is in order and contiguous.
- */
-struct gb_i2c_transfer_op {
- __le16 addr;
- __le16 flags;
- __le16 size;
-} __packed;
-
-struct gb_i2c_transfer_request {
- __le16 op_count;
- struct gb_i2c_transfer_op ops[0]; /* op_count of these */
-} __packed;
-struct gb_i2c_transfer_response {
- __u8 data[0]; /* inbound data */
-} __packed;
-
-
-/* GPIO */
-
-/* Greybus GPIO request types */
-#define GB_GPIO_TYPE_LINE_COUNT 0x02
-#define GB_GPIO_TYPE_ACTIVATE 0x03
-#define GB_GPIO_TYPE_DEACTIVATE 0x04
-#define GB_GPIO_TYPE_GET_DIRECTION 0x05
-#define GB_GPIO_TYPE_DIRECTION_IN 0x06
-#define GB_GPIO_TYPE_DIRECTION_OUT 0x07
-#define GB_GPIO_TYPE_GET_VALUE 0x08
-#define GB_GPIO_TYPE_SET_VALUE 0x09
-#define GB_GPIO_TYPE_SET_DEBOUNCE 0x0a
-#define GB_GPIO_TYPE_IRQ_TYPE 0x0b
-#define GB_GPIO_TYPE_IRQ_MASK 0x0c
-#define GB_GPIO_TYPE_IRQ_UNMASK 0x0d
-#define GB_GPIO_TYPE_IRQ_EVENT 0x0e
-
-#define GB_GPIO_IRQ_TYPE_NONE 0x00
-#define GB_GPIO_IRQ_TYPE_EDGE_RISING 0x01
-#define GB_GPIO_IRQ_TYPE_EDGE_FALLING 0x02
-#define GB_GPIO_IRQ_TYPE_EDGE_BOTH 0x03
-#define GB_GPIO_IRQ_TYPE_LEVEL_HIGH 0x04
-#define GB_GPIO_IRQ_TYPE_LEVEL_LOW 0x08
-
-/* line count request has no payload */
-struct gb_gpio_line_count_response {
- __u8 count;
-} __packed;
-
-struct gb_gpio_activate_request {
- __u8 which;
-} __packed;
-/* activate response has no payload */
-
-struct gb_gpio_deactivate_request {
- __u8 which;
-} __packed;
-/* deactivate response has no payload */
-
-struct gb_gpio_get_direction_request {
- __u8 which;
-} __packed;
-struct gb_gpio_get_direction_response {
- __u8 direction;
-} __packed;
-
-struct gb_gpio_direction_in_request {
- __u8 which;
-} __packed;
-/* direction in response has no payload */
-
-struct gb_gpio_direction_out_request {
- __u8 which;
- __u8 value;
-} __packed;
-/* direction out response has no payload */
-
-struct gb_gpio_get_value_request {
- __u8 which;
-} __packed;
-struct gb_gpio_get_value_response {
- __u8 value;
-} __packed;
-
-struct gb_gpio_set_value_request {
- __u8 which;
- __u8 value;
-} __packed;
-/* set value response has no payload */
-
-struct gb_gpio_set_debounce_request {
- __u8 which;
- __le16 usec;
-} __packed;
-/* debounce response has no payload */
-
-struct gb_gpio_irq_type_request {
- __u8 which;
- __u8 type;
-} __packed;
-/* irq type response has no payload */
-
-struct gb_gpio_irq_mask_request {
- __u8 which;
-} __packed;
-/* irq mask response has no payload */
-
-struct gb_gpio_irq_unmask_request {
- __u8 which;
-} __packed;
-/* irq unmask response has no payload */
-
-/* irq event requests originate on another module and are handled on the AP */
-struct gb_gpio_irq_event_request {
- __u8 which;
-} __packed;
-/* irq event has no response */
-
-
-/* PWM */
-
-/* Greybus PWM operation types */
-#define GB_PWM_TYPE_PWM_COUNT 0x02
-#define GB_PWM_TYPE_ACTIVATE 0x03
-#define GB_PWM_TYPE_DEACTIVATE 0x04
-#define GB_PWM_TYPE_CONFIG 0x05
-#define GB_PWM_TYPE_POLARITY 0x06
-#define GB_PWM_TYPE_ENABLE 0x07
-#define GB_PWM_TYPE_DISABLE 0x08
-
-/* pwm count request has no payload */
-struct gb_pwm_count_response {
- __u8 count;
-} __packed;
-
-struct gb_pwm_activate_request {
- __u8 which;
-} __packed;
-
-struct gb_pwm_deactivate_request {
- __u8 which;
-} __packed;
-
-struct gb_pwm_config_request {
- __u8 which;
- __le32 duty;
- __le32 period;
-} __packed;
-
-struct gb_pwm_polarity_request {
- __u8 which;
- __u8 polarity;
-} __packed;
-
-struct gb_pwm_enable_request {
- __u8 which;
-} __packed;
-
-struct gb_pwm_disable_request {
- __u8 which;
-} __packed;
-
-/* SPI */
-
-/* Should match up with modes in linux/spi/spi.h */
-#define GB_SPI_MODE_CPHA 0x01 /* clock phase */
-#define GB_SPI_MODE_CPOL 0x02 /* clock polarity */
-#define GB_SPI_MODE_MODE_0 (0 | 0) /* (original MicroWire) */
-#define GB_SPI_MODE_MODE_1 (0 | GB_SPI_MODE_CPHA)
-#define GB_SPI_MODE_MODE_2 (GB_SPI_MODE_CPOL | 0)
-#define GB_SPI_MODE_MODE_3 (GB_SPI_MODE_CPOL | GB_SPI_MODE_CPHA)
-#define GB_SPI_MODE_CS_HIGH 0x04 /* chipselect active high? */
-#define GB_SPI_MODE_LSB_FIRST 0x08 /* per-word bits-on-wire */
-#define GB_SPI_MODE_3WIRE 0x10 /* SI/SO signals shared */
-#define GB_SPI_MODE_LOOP 0x20 /* loopback mode */
-#define GB_SPI_MODE_NO_CS 0x40 /* 1 dev/bus, no chipselect */
-#define GB_SPI_MODE_READY 0x80 /* slave pulls low to pause */
-
-/* Should match up with flags in linux/spi/spi.h */
-#define GB_SPI_FLAG_HALF_DUPLEX BIT(0) /* can't do full duplex */
-#define GB_SPI_FLAG_NO_RX BIT(1) /* can't do buffer read */
-#define GB_SPI_FLAG_NO_TX BIT(2) /* can't do buffer write */
-
-/* Greybus spi operation types */
-#define GB_SPI_TYPE_MASTER_CONFIG 0x02
-#define GB_SPI_TYPE_DEVICE_CONFIG 0x03
-#define GB_SPI_TYPE_TRANSFER 0x04
-
-/* mode request has no payload */
-struct gb_spi_master_config_response {
- __le32 bits_per_word_mask;
- __le32 min_speed_hz;
- __le32 max_speed_hz;
- __le16 mode;
- __le16 flags;
- __u8 num_chipselect;
-} __packed;
-
-struct gb_spi_device_config_request {
- __u8 chip_select;
-} __packed;
-
-struct gb_spi_device_config_response {
- __le16 mode;
- __u8 bits_per_word;
- __le32 max_speed_hz;
- __u8 device_type;
-#define GB_SPI_SPI_DEV 0x00
-#define GB_SPI_SPI_NOR 0x01
-#define GB_SPI_SPI_MODALIAS 0x02
- __u8 name[32];
-} __packed;
-
-/**
- * struct gb_spi_transfer - a read/write buffer pair
- * @speed_hz: Select a speed other than the device default for this transfer. If
- * 0 the default (from @spi_device) is used.
- * @len: size of rx and tx buffers (in bytes)
- * @delay_usecs: microseconds to delay after this transfer before (optionally)
- * changing the chipselect status, then starting the next transfer or
- * completing this spi_message.
- * @cs_change: affects chipselect after this transfer completes
- * @bits_per_word: select a bits_per_word other than the device default for this
- * transfer. If 0 the default (from @spi_device) is used.
- */
-struct gb_spi_transfer {
- __le32 speed_hz;
- __le32 len;
- __le16 delay_usecs;
- __u8 cs_change;
- __u8 bits_per_word;
- __u8 xfer_flags;
-#define GB_SPI_XFER_READ 0x01
-#define GB_SPI_XFER_WRITE 0x02
-#define GB_SPI_XFER_INPROGRESS 0x04
-} __packed;
-
-struct gb_spi_transfer_request {
- __u8 chip_select; /* of the spi device */
- __u8 mode; /* of the spi device */
- __le16 count;
- struct gb_spi_transfer transfers[0]; /* count of these */
-} __packed;
-
-struct gb_spi_transfer_response {
- __u8 data[0]; /* inbound data */
-} __packed;
-
-/* Version of the Greybus SVC protocol we support */
-#define GB_SVC_VERSION_MAJOR 0x00
-#define GB_SVC_VERSION_MINOR 0x01
-
-/* Greybus SVC request types */
-#define GB_SVC_TYPE_PROTOCOL_VERSION 0x01
-#define GB_SVC_TYPE_SVC_HELLO 0x02
-#define GB_SVC_TYPE_INTF_DEVICE_ID 0x03
-#define GB_SVC_TYPE_INTF_RESET 0x06
-#define GB_SVC_TYPE_CONN_CREATE 0x07
-#define GB_SVC_TYPE_CONN_DESTROY 0x08
-#define GB_SVC_TYPE_DME_PEER_GET 0x09
-#define GB_SVC_TYPE_DME_PEER_SET 0x0a
-#define GB_SVC_TYPE_ROUTE_CREATE 0x0b
-#define GB_SVC_TYPE_ROUTE_DESTROY 0x0c
-#define GB_SVC_TYPE_TIMESYNC_ENABLE 0x0d
-#define GB_SVC_TYPE_TIMESYNC_DISABLE 0x0e
-#define GB_SVC_TYPE_TIMESYNC_AUTHORITATIVE 0x0f
-#define GB_SVC_TYPE_INTF_SET_PWRM 0x10
-#define GB_SVC_TYPE_INTF_EJECT 0x11
-#define GB_SVC_TYPE_PING 0x13
-#define GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET 0x14
-#define GB_SVC_TYPE_PWRMON_RAIL_NAMES_GET 0x15
-#define GB_SVC_TYPE_PWRMON_SAMPLE_GET 0x16
-#define GB_SVC_TYPE_PWRMON_INTF_SAMPLE_GET 0x17
-#define GB_SVC_TYPE_TIMESYNC_WAKE_PINS_ACQUIRE 0x18
-#define GB_SVC_TYPE_TIMESYNC_WAKE_PINS_RELEASE 0x19
-#define GB_SVC_TYPE_TIMESYNC_PING 0x1a
-#define GB_SVC_TYPE_MODULE_INSERTED 0x1f
-#define GB_SVC_TYPE_MODULE_REMOVED 0x20
-#define GB_SVC_TYPE_INTF_VSYS_ENABLE 0x21
-#define GB_SVC_TYPE_INTF_VSYS_DISABLE 0x22
-#define GB_SVC_TYPE_INTF_REFCLK_ENABLE 0x23
-#define GB_SVC_TYPE_INTF_REFCLK_DISABLE 0x24
-#define GB_SVC_TYPE_INTF_UNIPRO_ENABLE 0x25
-#define GB_SVC_TYPE_INTF_UNIPRO_DISABLE 0x26
-#define GB_SVC_TYPE_INTF_ACTIVATE 0x27
-#define GB_SVC_TYPE_INTF_RESUME 0x28
-#define GB_SVC_TYPE_INTF_MAILBOX_EVENT 0x29
-#define GB_SVC_TYPE_INTF_OOPS 0x2a
-
-/* Greybus SVC protocol status values */
-#define GB_SVC_OP_SUCCESS 0x00
-#define GB_SVC_OP_UNKNOWN_ERROR 0x01
-#define GB_SVC_INTF_NOT_DETECTED 0x02
-#define GB_SVC_INTF_NO_UPRO_LINK 0x03
-#define GB_SVC_INTF_UPRO_NOT_DOWN 0x04
-#define GB_SVC_INTF_UPRO_NOT_HIBERNATED 0x05
-#define GB_SVC_INTF_NO_V_SYS 0x06
-#define GB_SVC_INTF_V_CHG 0x07
-#define GB_SVC_INTF_WAKE_BUSY 0x08
-#define GB_SVC_INTF_NO_REFCLK 0x09
-#define GB_SVC_INTF_RELEASING 0x0a
-#define GB_SVC_INTF_NO_ORDER 0x0b
-#define GB_SVC_INTF_MBOX_SET 0x0c
-#define GB_SVC_INTF_BAD_MBOX 0x0d
-#define GB_SVC_INTF_OP_TIMEOUT 0x0e
-#define GB_SVC_PWRMON_OP_NOT_PRESENT 0x0f
-
-struct gb_svc_version_request {
- __u8 major;
- __u8 minor;
-} __packed;
-
-struct gb_svc_version_response {
- __u8 major;
- __u8 minor;
-} __packed;
-
-/* SVC protocol hello request */
-struct gb_svc_hello_request {
- __le16 endo_id;
- __u8 interface_id;
-} __packed;
-/* hello response has no payload */
-
-struct gb_svc_intf_device_id_request {
- __u8 intf_id;
- __u8 device_id;
-} __packed;
-/* device id response has no payload */
-
-struct gb_svc_intf_reset_request {
- __u8 intf_id;
-} __packed;
-/* interface reset response has no payload */
-
-struct gb_svc_intf_eject_request {
- __u8 intf_id;
-} __packed;
-/* interface eject response has no payload */
-
-struct gb_svc_conn_create_request {
- __u8 intf1_id;
- __le16 cport1_id;
- __u8 intf2_id;
- __le16 cport2_id;
- __u8 tc;
- __u8 flags;
-} __packed;
-/* connection create response has no payload */
-
-struct gb_svc_conn_destroy_request {
- __u8 intf1_id;
- __le16 cport1_id;
- __u8 intf2_id;
- __le16 cport2_id;
-} __packed;
-/* connection destroy response has no payload */
-
-struct gb_svc_dme_peer_get_request {
- __u8 intf_id;
- __le16 attr;
- __le16 selector;
-} __packed;
-
-struct gb_svc_dme_peer_get_response {
- __le16 result_code;
- __le32 attr_value;
-} __packed;
-
-struct gb_svc_dme_peer_set_request {
- __u8 intf_id;
- __le16 attr;
- __le16 selector;
- __le32 value;
-} __packed;
-
-struct gb_svc_dme_peer_set_response {
- __le16 result_code;
-} __packed;
-
-/* Greybus init-status values, currently retrieved using DME peer gets. */
-#define GB_INIT_SPI_BOOT_STARTED 0x02
-#define GB_INIT_TRUSTED_SPI_BOOT_FINISHED 0x03
-#define GB_INIT_UNTRUSTED_SPI_BOOT_FINISHED 0x04
-#define GB_INIT_BOOTROM_UNIPRO_BOOT_STARTED 0x06
-#define GB_INIT_BOOTROM_FALLBACK_UNIPRO_BOOT_STARTED 0x09
-#define GB_INIT_S2_LOADER_BOOT_STARTED 0x0D
-
-struct gb_svc_route_create_request {
- __u8 intf1_id;
- __u8 dev1_id;
- __u8 intf2_id;
- __u8 dev2_id;
-} __packed;
-/* route create response has no payload */
-
-struct gb_svc_route_destroy_request {
- __u8 intf1_id;
- __u8 intf2_id;
-} __packed;
-/* route destroy response has no payload */
-
-/* used for svc_intf_vsys_{enable,disable} */
-struct gb_svc_intf_vsys_request {
- __u8 intf_id;
-} __packed;
-
-struct gb_svc_intf_vsys_response {
- __u8 result_code;
-#define GB_SVC_INTF_VSYS_OK 0x00
- /* 0x01 is reserved */
-#define GB_SVC_INTF_VSYS_FAIL 0x02
-} __packed;
-
-/* used for svc_intf_refclk_{enable,disable} */
-struct gb_svc_intf_refclk_request {
- __u8 intf_id;
-} __packed;
-
-struct gb_svc_intf_refclk_response {
- __u8 result_code;
-#define GB_SVC_INTF_REFCLK_OK 0x00
- /* 0x01 is reserved */
-#define GB_SVC_INTF_REFCLK_FAIL 0x02
-} __packed;
-
-/* used for svc_intf_unipro_{enable,disable} */
-struct gb_svc_intf_unipro_request {
- __u8 intf_id;
-} __packed;
-
-struct gb_svc_intf_unipro_response {
- __u8 result_code;
-#define GB_SVC_INTF_UNIPRO_OK 0x00
- /* 0x01 is reserved */
-#define GB_SVC_INTF_UNIPRO_FAIL 0x02
-#define GB_SVC_INTF_UNIPRO_NOT_OFF 0x03
-} __packed;
-
-#define GB_SVC_UNIPRO_FAST_MODE 0x01
-#define GB_SVC_UNIPRO_SLOW_MODE 0x02
-#define GB_SVC_UNIPRO_FAST_AUTO_MODE 0x04
-#define GB_SVC_UNIPRO_SLOW_AUTO_MODE 0x05
-#define GB_SVC_UNIPRO_MODE_UNCHANGED 0x07
-#define GB_SVC_UNIPRO_HIBERNATE_MODE 0x11
-#define GB_SVC_UNIPRO_OFF_MODE 0x12
-
-#define GB_SVC_SMALL_AMPLITUDE 0x01
-#define GB_SVC_LARGE_AMPLITUDE 0x02
-
-#define GB_SVC_NO_DE_EMPHASIS 0x00
-#define GB_SVC_SMALL_DE_EMPHASIS 0x01
-#define GB_SVC_LARGE_DE_EMPHASIS 0x02
-
-#define GB_SVC_PWRM_RXTERMINATION 0x01
-#define GB_SVC_PWRM_TXTERMINATION 0x02
-#define GB_SVC_PWRM_LINE_RESET 0x04
-#define GB_SVC_PWRM_SCRAMBLING 0x20
-
-#define GB_SVC_PWRM_QUIRK_HSSER 0x00000001
-
-#define GB_SVC_UNIPRO_HS_SERIES_A 0x01
-#define GB_SVC_UNIPRO_HS_SERIES_B 0x02
-
-#define GB_SVC_SETPWRM_PWR_OK 0x00
-#define GB_SVC_SETPWRM_PWR_LOCAL 0x01
-#define GB_SVC_SETPWRM_PWR_REMOTE 0x02
-#define GB_SVC_SETPWRM_PWR_BUSY 0x03
-#define GB_SVC_SETPWRM_PWR_ERROR_CAP 0x04
-#define GB_SVC_SETPWRM_PWR_FATAL_ERROR 0x05
-
-struct gb_svc_l2_timer_cfg {
- __le16 tsb_fc0_protection_timeout;
- __le16 tsb_tc0_replay_timeout;
- __le16 tsb_afc0_req_timeout;
- __le16 tsb_fc1_protection_timeout;
- __le16 tsb_tc1_replay_timeout;
- __le16 tsb_afc1_req_timeout;
- __le16 reserved_for_tc2[3];
- __le16 reserved_for_tc3[3];
-} __packed;
-
-struct gb_svc_intf_set_pwrm_request {
- __u8 intf_id;
- __u8 hs_series;
- __u8 tx_mode;
- __u8 tx_gear;
- __u8 tx_nlanes;
- __u8 tx_amplitude;
- __u8 tx_hs_equalizer;
- __u8 rx_mode;
- __u8 rx_gear;
- __u8 rx_nlanes;
- __u8 flags;
- __le32 quirks;
- struct gb_svc_l2_timer_cfg local_l2timerdata, remote_l2timerdata;
-} __packed;
-
-struct gb_svc_intf_set_pwrm_response {
- __u8 result_code;
-} __packed;
-
-struct gb_svc_key_event_request {
- __le16 key_code;
-#define GB_KEYCODE_ARA 0x00
-
- __u8 key_event;
-#define GB_SVC_KEY_RELEASED 0x00
-#define GB_SVC_KEY_PRESSED 0x01
-} __packed;
-
-#define GB_SVC_PWRMON_MAX_RAIL_COUNT 254
-
-struct gb_svc_pwrmon_rail_count_get_response {
- __u8 rail_count;
-} __packed;
-
-#define GB_SVC_PWRMON_RAIL_NAME_BUFSIZE 32
-
-struct gb_svc_pwrmon_rail_names_get_response {
- __u8 status;
- __u8 name[0][GB_SVC_PWRMON_RAIL_NAME_BUFSIZE];
-} __packed;
-
-#define GB_SVC_PWRMON_TYPE_CURR 0x01
-#define GB_SVC_PWRMON_TYPE_VOL 0x02
-#define GB_SVC_PWRMON_TYPE_PWR 0x03
-
-#define GB_SVC_PWRMON_GET_SAMPLE_OK 0x00
-#define GB_SVC_PWRMON_GET_SAMPLE_INVAL 0x01
-#define GB_SVC_PWRMON_GET_SAMPLE_NOSUPP 0x02
-#define GB_SVC_PWRMON_GET_SAMPLE_HWERR 0x03
-
-struct gb_svc_pwrmon_sample_get_request {
- __u8 rail_id;
- __u8 measurement_type;
-} __packed;
-
-struct gb_svc_pwrmon_sample_get_response {
- __u8 result;
- __le32 measurement;
-} __packed;
-
-struct gb_svc_pwrmon_intf_sample_get_request {
- __u8 intf_id;
- __u8 measurement_type;
-} __packed;
-
-struct gb_svc_pwrmon_intf_sample_get_response {
- __u8 result;
- __le32 measurement;
-} __packed;
-
-#define GB_SVC_MODULE_INSERTED_FLAG_NO_PRIMARY 0x0001
-
-struct gb_svc_module_inserted_request {
- __u8 primary_intf_id;
- __u8 intf_count;
- __le16 flags;
-} __packed;
-/* module_inserted response has no payload */
-
-struct gb_svc_module_removed_request {
- __u8 primary_intf_id;
-} __packed;
-/* module_removed response has no payload */
-
-struct gb_svc_intf_activate_request {
- __u8 intf_id;
-} __packed;
-
-#define GB_SVC_INTF_TYPE_UNKNOWN 0x00
-#define GB_SVC_INTF_TYPE_DUMMY 0x01
-#define GB_SVC_INTF_TYPE_UNIPRO 0x02
-#define GB_SVC_INTF_TYPE_GREYBUS 0x03
-
-struct gb_svc_intf_activate_response {
- __u8 status;
- __u8 intf_type;
-} __packed;
-
-struct gb_svc_intf_resume_request {
- __u8 intf_id;
-} __packed;
-
-struct gb_svc_intf_resume_response {
- __u8 status;
-} __packed;
-
-#define GB_SVC_INTF_MAILBOX_NONE 0x00
-#define GB_SVC_INTF_MAILBOX_AP 0x01
-#define GB_SVC_INTF_MAILBOX_GREYBUS 0x02
-
-struct gb_svc_intf_mailbox_event_request {
- __u8 intf_id;
- __le16 result_code;
- __le32 mailbox;
-} __packed;
-/* intf_mailbox_event response has no payload */
-
-struct gb_svc_intf_oops_request {
- __u8 intf_id;
- __u8 reason;
-} __packed;
-/* intf_oops response has no payload */
-
-
-/* RAW */
-
-/* Greybus raw request types */
-#define GB_RAW_TYPE_SEND 0x02
-
-struct gb_raw_send_request {
- __le32 len;
- __u8 data[0];
-} __packed;
-
-
-/* UART */
-
-/* Greybus UART operation types */
-#define GB_UART_TYPE_SEND_DATA 0x02
-#define GB_UART_TYPE_RECEIVE_DATA 0x03 /* Unsolicited data */
-#define GB_UART_TYPE_SET_LINE_CODING 0x04
-#define GB_UART_TYPE_SET_CONTROL_LINE_STATE 0x05
-#define GB_UART_TYPE_SEND_BREAK 0x06
-#define GB_UART_TYPE_SERIAL_STATE 0x07 /* Unsolicited data */
-#define GB_UART_TYPE_RECEIVE_CREDITS 0x08
-#define GB_UART_TYPE_FLUSH_FIFOS 0x09
-
-/* Represents data from AP -> Module */
-struct gb_uart_send_data_request {
- __le16 size;
- __u8 data[0];
-} __packed;
-
-/* recv-data-request flags */
-#define GB_UART_RECV_FLAG_FRAMING 0x01 /* Framing error */
-#define GB_UART_RECV_FLAG_PARITY 0x02 /* Parity error */
-#define GB_UART_RECV_FLAG_OVERRUN 0x04 /* Overrun error */
-#define GB_UART_RECV_FLAG_BREAK 0x08 /* Break */
-
-/* Represents data from Module -> AP */
-struct gb_uart_recv_data_request {
- __le16 size;
- __u8 flags;
- __u8 data[0];
-} __packed;
-
-struct gb_uart_receive_credits_request {
- __le16 count;
-} __packed;
-
-struct gb_uart_set_line_coding_request {
- __le32 rate;
- __u8 format;
-#define GB_SERIAL_1_STOP_BITS 0
-#define GB_SERIAL_1_5_STOP_BITS 1
-#define GB_SERIAL_2_STOP_BITS 2
-
- __u8 parity;
-#define GB_SERIAL_NO_PARITY 0
-#define GB_SERIAL_ODD_PARITY 1
-#define GB_SERIAL_EVEN_PARITY 2
-#define GB_SERIAL_MARK_PARITY 3
-#define GB_SERIAL_SPACE_PARITY 4
-
- __u8 data_bits;
-
- __u8 flow_control;
-#define GB_SERIAL_AUTO_RTSCTS_EN 0x1
-} __packed;
-
-/* output control lines */
-#define GB_UART_CTRL_DTR 0x01
-#define GB_UART_CTRL_RTS 0x02
-
-struct gb_uart_set_control_line_state_request {
- __u8 control;
-} __packed;
-
-struct gb_uart_set_break_request {
- __u8 state;
-} __packed;
-
-/* input control lines and line errors */
-#define GB_UART_CTRL_DCD 0x01
-#define GB_UART_CTRL_DSR 0x02
-#define GB_UART_CTRL_RI 0x04
-
-struct gb_uart_serial_state_request {
- __u8 control;
-} __packed;
-
-struct gb_uart_serial_flush_request {
- __u8 flags;
-#define GB_SERIAL_FLAG_FLUSH_TRANSMITTER 0x01
-#define GB_SERIAL_FLAG_FLUSH_RECEIVER 0x02
-} __packed;
-
-/* Loopback */
-
-/* Greybus loopback request types */
-#define GB_LOOPBACK_TYPE_PING 0x02
-#define GB_LOOPBACK_TYPE_TRANSFER 0x03
-#define GB_LOOPBACK_TYPE_SINK 0x04
-
-/*
- * Loopback request/response header format should be identical
- * to simplify bandwidth and data movement analysis.
- */
-struct gb_loopback_transfer_request {
- __le32 len;
- __le32 reserved0;
- __le32 reserved1;
- __u8 data[0];
-} __packed;
-
-struct gb_loopback_transfer_response {
- __le32 len;
- __le32 reserved0;
- __le32 reserved1;
- __u8 data[0];
-} __packed;
-
-/* SDIO */
-/* Greybus SDIO operation types */
-#define GB_SDIO_TYPE_GET_CAPABILITIES 0x02
-#define GB_SDIO_TYPE_SET_IOS 0x03
-#define GB_SDIO_TYPE_COMMAND 0x04
-#define GB_SDIO_TYPE_TRANSFER 0x05
-#define GB_SDIO_TYPE_EVENT 0x06
-
-/* get caps response: request has no payload */
-struct gb_sdio_get_caps_response {
- __le32 caps;
-#define GB_SDIO_CAP_NONREMOVABLE 0x00000001
-#define GB_SDIO_CAP_4_BIT_DATA 0x00000002
-#define GB_SDIO_CAP_8_BIT_DATA 0x00000004
-#define GB_SDIO_CAP_MMC_HS 0x00000008
-#define GB_SDIO_CAP_SD_HS 0x00000010
-#define GB_SDIO_CAP_ERASE 0x00000020
-#define GB_SDIO_CAP_1_2V_DDR 0x00000040
-#define GB_SDIO_CAP_1_8V_DDR 0x00000080
-#define GB_SDIO_CAP_POWER_OFF_CARD 0x00000100
-#define GB_SDIO_CAP_UHS_SDR12 0x00000200
-#define GB_SDIO_CAP_UHS_SDR25 0x00000400
-#define GB_SDIO_CAP_UHS_SDR50 0x00000800
-#define GB_SDIO_CAP_UHS_SDR104 0x00001000
-#define GB_SDIO_CAP_UHS_DDR50 0x00002000
-#define GB_SDIO_CAP_DRIVER_TYPE_A 0x00004000
-#define GB_SDIO_CAP_DRIVER_TYPE_C 0x00008000
-#define GB_SDIO_CAP_DRIVER_TYPE_D 0x00010000
-#define GB_SDIO_CAP_HS200_1_2V 0x00020000
-#define GB_SDIO_CAP_HS200_1_8V 0x00040000
-#define GB_SDIO_CAP_HS400_1_2V 0x00080000
-#define GB_SDIO_CAP_HS400_1_8V 0x00100000
-
- /* see possible values below at vdd */
- __le32 ocr;
- __le32 f_min;
- __le32 f_max;
- __le16 max_blk_count;
- __le16 max_blk_size;
-} __packed;
-
-/* set ios request: response has no payload */
-struct gb_sdio_set_ios_request {
- __le32 clock;
- __le32 vdd;
-#define GB_SDIO_VDD_165_195 0x00000001
-#define GB_SDIO_VDD_20_21 0x00000002
-#define GB_SDIO_VDD_21_22 0x00000004
-#define GB_SDIO_VDD_22_23 0x00000008
-#define GB_SDIO_VDD_23_24 0x00000010
-#define GB_SDIO_VDD_24_25 0x00000020
-#define GB_SDIO_VDD_25_26 0x00000040
-#define GB_SDIO_VDD_26_27 0x00000080
-#define GB_SDIO_VDD_27_28 0x00000100
-#define GB_SDIO_VDD_28_29 0x00000200
-#define GB_SDIO_VDD_29_30 0x00000400
-#define GB_SDIO_VDD_30_31 0x00000800
-#define GB_SDIO_VDD_31_32 0x00001000
-#define GB_SDIO_VDD_32_33 0x00002000
-#define GB_SDIO_VDD_33_34 0x00004000
-#define GB_SDIO_VDD_34_35 0x00008000
-#define GB_SDIO_VDD_35_36 0x00010000
-
- __u8 bus_mode;
-#define GB_SDIO_BUSMODE_OPENDRAIN 0x00
-#define GB_SDIO_BUSMODE_PUSHPULL 0x01
-
- __u8 power_mode;
-#define GB_SDIO_POWER_OFF 0x00
-#define GB_SDIO_POWER_UP 0x01
-#define GB_SDIO_POWER_ON 0x02
-#define GB_SDIO_POWER_UNDEFINED 0x03
-
- __u8 bus_width;
-#define GB_SDIO_BUS_WIDTH_1 0x00
-#define GB_SDIO_BUS_WIDTH_4 0x02
-#define GB_SDIO_BUS_WIDTH_8 0x03
-
- __u8 timing;
-#define GB_SDIO_TIMING_LEGACY 0x00
-#define GB_SDIO_TIMING_MMC_HS 0x01
-#define GB_SDIO_TIMING_SD_HS 0x02
-#define GB_SDIO_TIMING_UHS_SDR12 0x03
-#define GB_SDIO_TIMING_UHS_SDR25 0x04
-#define GB_SDIO_TIMING_UHS_SDR50 0x05
-#define GB_SDIO_TIMING_UHS_SDR104 0x06
-#define GB_SDIO_TIMING_UHS_DDR50 0x07
-#define GB_SDIO_TIMING_MMC_DDR52 0x08
-#define GB_SDIO_TIMING_MMC_HS200 0x09
-#define GB_SDIO_TIMING_MMC_HS400 0x0A
-
- __u8 signal_voltage;
-#define GB_SDIO_SIGNAL_VOLTAGE_330 0x00
-#define GB_SDIO_SIGNAL_VOLTAGE_180 0x01
-#define GB_SDIO_SIGNAL_VOLTAGE_120 0x02
-
- __u8 drv_type;
-#define GB_SDIO_SET_DRIVER_TYPE_B 0x00
-#define GB_SDIO_SET_DRIVER_TYPE_A 0x01
-#define GB_SDIO_SET_DRIVER_TYPE_C 0x02
-#define GB_SDIO_SET_DRIVER_TYPE_D 0x03
-} __packed;
-
-/* command request */
-struct gb_sdio_command_request {
- __u8 cmd;
- __u8 cmd_flags;
-#define GB_SDIO_RSP_NONE 0x00
-#define GB_SDIO_RSP_PRESENT 0x01
-#define GB_SDIO_RSP_136 0x02
-#define GB_SDIO_RSP_CRC 0x04
-#define GB_SDIO_RSP_BUSY 0x08
-#define GB_SDIO_RSP_OPCODE 0x10
-
- __u8 cmd_type;
-#define GB_SDIO_CMD_AC 0x00
-#define GB_SDIO_CMD_ADTC 0x01
-#define GB_SDIO_CMD_BC 0x02
-#define GB_SDIO_CMD_BCR 0x03
-
- __le32 cmd_arg;
- __le16 data_blocks;
- __le16 data_blksz;
-} __packed;
-
-struct gb_sdio_command_response {
- __le32 resp[4];
-} __packed;
-
-/* transfer request */
-struct gb_sdio_transfer_request {
- __u8 data_flags;
-#define GB_SDIO_DATA_WRITE 0x01
-#define GB_SDIO_DATA_READ 0x02
-#define GB_SDIO_DATA_STREAM 0x04
-
- __le16 data_blocks;
- __le16 data_blksz;
- __u8 data[0];
-} __packed;
-
-struct gb_sdio_transfer_response {
- __le16 data_blocks;
- __le16 data_blksz;
- __u8 data[0];
-} __packed;
-
-/* event request: generated by module and is defined as unidirectional */
-struct gb_sdio_event_request {
- __u8 event;
-#define GB_SDIO_CARD_INSERTED 0x01
-#define GB_SDIO_CARD_REMOVED 0x02
-#define GB_SDIO_WP 0x04
-} __packed;
-
-/* Camera */
-
-/* Greybus Camera request types */
-#define GB_CAMERA_TYPE_CAPABILITIES 0x02
-#define GB_CAMERA_TYPE_CONFIGURE_STREAMS 0x03
-#define GB_CAMERA_TYPE_CAPTURE 0x04
-#define GB_CAMERA_TYPE_FLUSH 0x05
-#define GB_CAMERA_TYPE_METADATA 0x06
-
-#define GB_CAMERA_MAX_STREAMS 4
-#define GB_CAMERA_MAX_SETTINGS_SIZE 8192
-
-/* Greybus Camera Configure Streams request payload */
-struct gb_camera_stream_config_request {
- __le16 width;
- __le16 height;
- __le16 format;
- __le16 padding;
-} __packed;
-
-struct gb_camera_configure_streams_request {
- __u8 num_streams;
- __u8 flags;
-#define GB_CAMERA_CONFIGURE_STREAMS_TEST_ONLY 0x01
- __le16 padding;
- struct gb_camera_stream_config_request config[0];
-} __packed;
-
-/* Greybus Camera Configure Streams response payload */
-struct gb_camera_stream_config_response {
- __le16 width;
- __le16 height;
- __le16 format;
- __u8 virtual_channel;
- __u8 data_type[2];
- __le16 max_pkt_size;
- __u8 padding;
- __le32 max_size;
-} __packed;
-
-struct gb_camera_configure_streams_response {
- __u8 num_streams;
-#define GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED 0x01
- __u8 flags;
- __u8 padding[2];
- __le32 data_rate;
- struct gb_camera_stream_config_response config[0];
-};
-
-/* Greybus Camera Capture request payload - response has no payload */
-struct gb_camera_capture_request {
- __le32 request_id;
- __u8 streams;
- __u8 padding;
- __le16 num_frames;
- __u8 settings[0];
-} __packed;
-
-/* Greybus Camera Flush response payload - request has no payload */
-struct gb_camera_flush_response {
- __le32 request_id;
-} __packed;
-
-/* Greybus Camera Metadata request payload - operation has no response */
-struct gb_camera_metadata_request {
- __le32 request_id;
- __le16 frame_number;
- __u8 stream;
- __u8 padding;
- __u8 metadata[0];
-} __packed;
-
-/* Lights */
-
-/* Greybus Lights request types */
-#define GB_LIGHTS_TYPE_GET_LIGHTS 0x02
-#define GB_LIGHTS_TYPE_GET_LIGHT_CONFIG 0x03
-#define GB_LIGHTS_TYPE_GET_CHANNEL_CONFIG 0x04
-#define GB_LIGHTS_TYPE_GET_CHANNEL_FLASH_CONFIG 0x05
-#define GB_LIGHTS_TYPE_SET_BRIGHTNESS 0x06
-#define GB_LIGHTS_TYPE_SET_BLINK 0x07
-#define GB_LIGHTS_TYPE_SET_COLOR 0x08
-#define GB_LIGHTS_TYPE_SET_FADE 0x09
-#define GB_LIGHTS_TYPE_EVENT 0x0A
-#define GB_LIGHTS_TYPE_SET_FLASH_INTENSITY 0x0B
-#define GB_LIGHTS_TYPE_SET_FLASH_STROBE 0x0C
-#define GB_LIGHTS_TYPE_SET_FLASH_TIMEOUT 0x0D
-#define GB_LIGHTS_TYPE_GET_FLASH_FAULT 0x0E
-
-/* Greybus Light modes */
-
-/*
- * if you add any specific mode below, update also the
- * GB_CHANNEL_MODE_DEFINED_RANGE value accordingly
- */
-#define GB_CHANNEL_MODE_NONE 0x00000000
-#define GB_CHANNEL_MODE_BATTERY 0x00000001
-#define GB_CHANNEL_MODE_POWER 0x00000002
-#define GB_CHANNEL_MODE_WIRELESS 0x00000004
-#define GB_CHANNEL_MODE_BLUETOOTH 0x00000008
-#define GB_CHANNEL_MODE_KEYBOARD 0x00000010
-#define GB_CHANNEL_MODE_BUTTONS 0x00000020
-#define GB_CHANNEL_MODE_NOTIFICATION 0x00000040
-#define GB_CHANNEL_MODE_ATTENTION 0x00000080
-#define GB_CHANNEL_MODE_FLASH 0x00000100
-#define GB_CHANNEL_MODE_TORCH 0x00000200
-#define GB_CHANNEL_MODE_INDICATOR 0x00000400
-
-/* Lights Mode valid bit values */
-#define GB_CHANNEL_MODE_DEFINED_RANGE 0x000004FF
-#define GB_CHANNEL_MODE_VENDOR_RANGE 0x00F00000
-
-/* Greybus Light Channels Flags */
-#define GB_LIGHT_CHANNEL_MULTICOLOR 0x00000001
-#define GB_LIGHT_CHANNEL_FADER 0x00000002
-#define GB_LIGHT_CHANNEL_BLINK 0x00000004
-
-/* get count of lights in module */
-struct gb_lights_get_lights_response {
- __u8 lights_count;
-} __packed;
-
-/* light config request payload */
-struct gb_lights_get_light_config_request {
- __u8 id;
-} __packed;
-
-/* light config response payload */
-struct gb_lights_get_light_config_response {
- __u8 channel_count;
- __u8 name[32];
-} __packed;
-
-/* channel config request payload */
-struct gb_lights_get_channel_config_request {
- __u8 light_id;
- __u8 channel_id;
-} __packed;
-
-/* channel flash config request payload */
-struct gb_lights_get_channel_flash_config_request {
- __u8 light_id;
- __u8 channel_id;
-} __packed;
-
-/* channel config response payload */
-struct gb_lights_get_channel_config_response {
- __u8 max_brightness;
- __le32 flags;
- __le32 color;
- __u8 color_name[32];
- __le32 mode;
- __u8 mode_name[32];
-} __packed;
-
-/* channel flash config response payload */
-struct gb_lights_get_channel_flash_config_response {
- __le32 intensity_min_uA;
- __le32 intensity_max_uA;
- __le32 intensity_step_uA;
- __le32 timeout_min_us;
- __le32 timeout_max_us;
- __le32 timeout_step_us;
-} __packed;
-
-/* blink request payload: response have no payload */
-struct gb_lights_blink_request {
- __u8 light_id;
- __u8 channel_id;
- __le16 time_on_ms;
- __le16 time_off_ms;
-} __packed;
-
-/* set brightness request payload: response have no payload */
-struct gb_lights_set_brightness_request {
- __u8 light_id;
- __u8 channel_id;
- __u8 brightness;
-} __packed;
-
-/* set color request payload: response have no payload */
-struct gb_lights_set_color_request {
- __u8 light_id;
- __u8 channel_id;
- __le32 color;
-} __packed;
-
-/* set fade request payload: response have no payload */
-struct gb_lights_set_fade_request {
- __u8 light_id;
- __u8 channel_id;
- __u8 fade_in;
- __u8 fade_out;
-} __packed;
-
-/* event request: generated by module */
-struct gb_lights_event_request {
- __u8 light_id;
- __u8 event;
-#define GB_LIGHTS_LIGHT_CONFIG 0x01
-} __packed;
-
-/* set flash intensity request payload: response have no payload */
-struct gb_lights_set_flash_intensity_request {
- __u8 light_id;
- __u8 channel_id;
- __le32 intensity_uA;
-} __packed;
-
-/* set flash strobe state request payload: response have no payload */
-struct gb_lights_set_flash_strobe_request {
- __u8 light_id;
- __u8 channel_id;
- __u8 state;
-} __packed;
-
-/* set flash timeout request payload: response have no payload */
-struct gb_lights_set_flash_timeout_request {
- __u8 light_id;
- __u8 channel_id;
- __le32 timeout_us;
-} __packed;
-
-/* get flash fault request payload */
-struct gb_lights_get_flash_fault_request {
- __u8 light_id;
- __u8 channel_id;
-} __packed;
-
-/* get flash fault response payload */
-struct gb_lights_get_flash_fault_response {
- __le32 fault;
-#define GB_LIGHTS_FLASH_FAULT_OVER_VOLTAGE 0x00000000
-#define GB_LIGHTS_FLASH_FAULT_TIMEOUT 0x00000001
-#define GB_LIGHTS_FLASH_FAULT_OVER_TEMPERATURE 0x00000002
-#define GB_LIGHTS_FLASH_FAULT_SHORT_CIRCUIT 0x00000004
-#define GB_LIGHTS_FLASH_FAULT_OVER_CURRENT 0x00000008
-#define GB_LIGHTS_FLASH_FAULT_INDICATOR 0x00000010
-#define GB_LIGHTS_FLASH_FAULT_UNDER_VOLTAGE 0x00000020
-#define GB_LIGHTS_FLASH_FAULT_INPUT_VOLTAGE 0x00000040
-#define GB_LIGHTS_FLASH_FAULT_LED_OVER_TEMPERATURE 0x00000080
-} __packed;
-
-/* Audio */
-
-#define GB_AUDIO_TYPE_GET_TOPOLOGY_SIZE 0x02
-#define GB_AUDIO_TYPE_GET_TOPOLOGY 0x03
-#define GB_AUDIO_TYPE_GET_CONTROL 0x04
-#define GB_AUDIO_TYPE_SET_CONTROL 0x05
-#define GB_AUDIO_TYPE_ENABLE_WIDGET 0x06
-#define GB_AUDIO_TYPE_DISABLE_WIDGET 0x07
-#define GB_AUDIO_TYPE_GET_PCM 0x08
-#define GB_AUDIO_TYPE_SET_PCM 0x09
-#define GB_AUDIO_TYPE_SET_TX_DATA_SIZE 0x0a
- /* 0x0b unused */
-#define GB_AUDIO_TYPE_ACTIVATE_TX 0x0c
-#define GB_AUDIO_TYPE_DEACTIVATE_TX 0x0d
-#define GB_AUDIO_TYPE_SET_RX_DATA_SIZE 0x0e
- /* 0x0f unused */
-#define GB_AUDIO_TYPE_ACTIVATE_RX 0x10
-#define GB_AUDIO_TYPE_DEACTIVATE_RX 0x11
-#define GB_AUDIO_TYPE_JACK_EVENT 0x12
-#define GB_AUDIO_TYPE_BUTTON_EVENT 0x13
-#define GB_AUDIO_TYPE_STREAMING_EVENT 0x14
-#define GB_AUDIO_TYPE_SEND_DATA 0x15
-
-/* Module must be able to buffer 10ms of audio data, minimum */
-#define GB_AUDIO_SAMPLE_BUFFER_MIN_US 10000
-
-#define GB_AUDIO_PCM_NAME_MAX 32
-#define AUDIO_DAI_NAME_MAX 32
-#define AUDIO_CONTROL_NAME_MAX 32
-#define AUDIO_CTL_ELEM_NAME_MAX 44
-#define AUDIO_ENUM_NAME_MAX 64
-#define AUDIO_WIDGET_NAME_MAX 32
-
-/* See SNDRV_PCM_FMTBIT_* in Linux source */
-#define GB_AUDIO_PCM_FMT_S8 BIT(0)
-#define GB_AUDIO_PCM_FMT_U8 BIT(1)
-#define GB_AUDIO_PCM_FMT_S16_LE BIT(2)
-#define GB_AUDIO_PCM_FMT_S16_BE BIT(3)
-#define GB_AUDIO_PCM_FMT_U16_LE BIT(4)
-#define GB_AUDIO_PCM_FMT_U16_BE BIT(5)
-#define GB_AUDIO_PCM_FMT_S24_LE BIT(6)
-#define GB_AUDIO_PCM_FMT_S24_BE BIT(7)
-#define GB_AUDIO_PCM_FMT_U24_LE BIT(8)
-#define GB_AUDIO_PCM_FMT_U24_BE BIT(9)
-#define GB_AUDIO_PCM_FMT_S32_LE BIT(10)
-#define GB_AUDIO_PCM_FMT_S32_BE BIT(11)
-#define GB_AUDIO_PCM_FMT_U32_LE BIT(12)
-#define GB_AUDIO_PCM_FMT_U32_BE BIT(13)
-
-/* See SNDRV_PCM_RATE_* in Linux source */
-#define GB_AUDIO_PCM_RATE_5512 BIT(0)
-#define GB_AUDIO_PCM_RATE_8000 BIT(1)
-#define GB_AUDIO_PCM_RATE_11025 BIT(2)
-#define GB_AUDIO_PCM_RATE_16000 BIT(3)
-#define GB_AUDIO_PCM_RATE_22050 BIT(4)
-#define GB_AUDIO_PCM_RATE_32000 BIT(5)
-#define GB_AUDIO_PCM_RATE_44100 BIT(6)
-#define GB_AUDIO_PCM_RATE_48000 BIT(7)
-#define GB_AUDIO_PCM_RATE_64000 BIT(8)
-#define GB_AUDIO_PCM_RATE_88200 BIT(9)
-#define GB_AUDIO_PCM_RATE_96000 BIT(10)
-#define GB_AUDIO_PCM_RATE_176400 BIT(11)
-#define GB_AUDIO_PCM_RATE_192000 BIT(12)
-
-#define GB_AUDIO_STREAM_TYPE_CAPTURE 0x1
-#define GB_AUDIO_STREAM_TYPE_PLAYBACK 0x2
-
-#define GB_AUDIO_CTL_ELEM_ACCESS_READ BIT(0)
-#define GB_AUDIO_CTL_ELEM_ACCESS_WRITE BIT(1)
-
-/* See SNDRV_CTL_ELEM_TYPE_* in Linux source */
-#define GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN 0x01
-#define GB_AUDIO_CTL_ELEM_TYPE_INTEGER 0x02
-#define GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED 0x03
-#define GB_AUDIO_CTL_ELEM_TYPE_INTEGER64 0x06
-
-/* See SNDRV_CTL_ELEM_IFACE_* in Linux source */
-#define GB_AUDIO_CTL_ELEM_IFACE_CARD 0x00
-#define GB_AUDIO_CTL_ELEM_IFACE_HWDEP 0x01
-#define GB_AUDIO_CTL_ELEM_IFACE_MIXER 0x02
-#define GB_AUDIO_CTL_ELEM_IFACE_PCM 0x03
-#define GB_AUDIO_CTL_ELEM_IFACE_RAWMIDI 0x04
-#define GB_AUDIO_CTL_ELEM_IFACE_TIMER 0x05
-#define GB_AUDIO_CTL_ELEM_IFACE_SEQUENCER 0x06
-
-/* SNDRV_CTL_ELEM_ACCESS_* in Linux source */
-#define GB_AUDIO_ACCESS_READ BIT(0)
-#define GB_AUDIO_ACCESS_WRITE BIT(1)
-#define GB_AUDIO_ACCESS_VOLATILE BIT(2)
-#define GB_AUDIO_ACCESS_TIMESTAMP BIT(3)
-#define GB_AUDIO_ACCESS_TLV_READ BIT(4)
-#define GB_AUDIO_ACCESS_TLV_WRITE BIT(5)
-#define GB_AUDIO_ACCESS_TLV_COMMAND BIT(6)
-#define GB_AUDIO_ACCESS_INACTIVE BIT(7)
-#define GB_AUDIO_ACCESS_LOCK BIT(8)
-#define GB_AUDIO_ACCESS_OWNER BIT(9)
-
-/* enum snd_soc_dapm_type */
-#define GB_AUDIO_WIDGET_TYPE_INPUT 0x0
-#define GB_AUDIO_WIDGET_TYPE_OUTPUT 0x1
-#define GB_AUDIO_WIDGET_TYPE_MUX 0x2
-#define GB_AUDIO_WIDGET_TYPE_VIRT_MUX 0x3
-#define GB_AUDIO_WIDGET_TYPE_VALUE_MUX 0x4
-#define GB_AUDIO_WIDGET_TYPE_MIXER 0x5
-#define GB_AUDIO_WIDGET_TYPE_MIXER_NAMED_CTL 0x6
-#define GB_AUDIO_WIDGET_TYPE_PGA 0x7
-#define GB_AUDIO_WIDGET_TYPE_OUT_DRV 0x8
-#define GB_AUDIO_WIDGET_TYPE_ADC 0x9
-#define GB_AUDIO_WIDGET_TYPE_DAC 0xa
-#define GB_AUDIO_WIDGET_TYPE_MICBIAS 0xb
-#define GB_AUDIO_WIDGET_TYPE_MIC 0xc
-#define GB_AUDIO_WIDGET_TYPE_HP 0xd
-#define GB_AUDIO_WIDGET_TYPE_SPK 0xe
-#define GB_AUDIO_WIDGET_TYPE_LINE 0xf
-#define GB_AUDIO_WIDGET_TYPE_SWITCH 0x10
-#define GB_AUDIO_WIDGET_TYPE_VMID 0x11
-#define GB_AUDIO_WIDGET_TYPE_PRE 0x12
-#define GB_AUDIO_WIDGET_TYPE_POST 0x13
-#define GB_AUDIO_WIDGET_TYPE_SUPPLY 0x14
-#define GB_AUDIO_WIDGET_TYPE_REGULATOR_SUPPLY 0x15
-#define GB_AUDIO_WIDGET_TYPE_CLOCK_SUPPLY 0x16
-#define GB_AUDIO_WIDGET_TYPE_AIF_IN 0x17
-#define GB_AUDIO_WIDGET_TYPE_AIF_OUT 0x18
-#define GB_AUDIO_WIDGET_TYPE_SIGGEN 0x19
-#define GB_AUDIO_WIDGET_TYPE_DAI_IN 0x1a
-#define GB_AUDIO_WIDGET_TYPE_DAI_OUT 0x1b
-#define GB_AUDIO_WIDGET_TYPE_DAI_LINK 0x1c
-
-#define GB_AUDIO_WIDGET_STATE_DISABLED 0x01
-#define GB_AUDIO_WIDGET_STATE_ENAABLED 0x02
-
-#define GB_AUDIO_JACK_EVENT_INSERTION 0x1
-#define GB_AUDIO_JACK_EVENT_REMOVAL 0x2
-
-#define GB_AUDIO_BUTTON_EVENT_PRESS 0x1
-#define GB_AUDIO_BUTTON_EVENT_RELEASE 0x2
-
-#define GB_AUDIO_STREAMING_EVENT_UNSPECIFIED 0x1
-#define GB_AUDIO_STREAMING_EVENT_HALT 0x2
-#define GB_AUDIO_STREAMING_EVENT_INTERNAL_ERROR 0x3
-#define GB_AUDIO_STREAMING_EVENT_PROTOCOL_ERROR 0x4
-#define GB_AUDIO_STREAMING_EVENT_FAILURE 0x5
-#define GB_AUDIO_STREAMING_EVENT_UNDERRUN 0x6
-#define GB_AUDIO_STREAMING_EVENT_OVERRUN 0x7
-#define GB_AUDIO_STREAMING_EVENT_CLOCKING 0x8
-#define GB_AUDIO_STREAMING_EVENT_DATA_LEN 0x9
-
-#define GB_AUDIO_INVALID_INDEX 0xff
-
-/* enum snd_jack_types */
-#define GB_AUDIO_JACK_HEADPHONE 0x0000001
-#define GB_AUDIO_JACK_MICROPHONE 0x0000002
-#define GB_AUDIO_JACK_HEADSET (GB_AUDIO_JACK_HEADPHONE | \
- GB_AUDIO_JACK_MICROPHONE)
-#define GB_AUDIO_JACK_LINEOUT 0x0000004
-#define GB_AUDIO_JACK_MECHANICAL 0x0000008
-#define GB_AUDIO_JACK_VIDEOOUT 0x0000010
-#define GB_AUDIO_JACK_AVOUT (GB_AUDIO_JACK_LINEOUT | \
- GB_AUDIO_JACK_VIDEOOUT)
-#define GB_AUDIO_JACK_LINEIN 0x0000020
-#define GB_AUDIO_JACK_OC_HPHL 0x0000040
-#define GB_AUDIO_JACK_OC_HPHR 0x0000080
-#define GB_AUDIO_JACK_MICROPHONE2 0x0000200
-#define GB_AUDIO_JACK_ANC_HEADPHONE (GB_AUDIO_JACK_HEADPHONE | \
- GB_AUDIO_JACK_MICROPHONE | \
- GB_AUDIO_JACK_MICROPHONE2)
-/* Kept separate from switches to facilitate implementation */
-#define GB_AUDIO_JACK_BTN_0 0x4000000
-#define GB_AUDIO_JACK_BTN_1 0x2000000
-#define GB_AUDIO_JACK_BTN_2 0x1000000
-#define GB_AUDIO_JACK_BTN_3 0x0800000
-
-struct gb_audio_pcm {
- __u8 stream_name[GB_AUDIO_PCM_NAME_MAX];
- __le32 formats; /* GB_AUDIO_PCM_FMT_* */
- __le32 rates; /* GB_AUDIO_PCM_RATE_* */
- __u8 chan_min;
- __u8 chan_max;
- __u8 sig_bits; /* number of bits of content */
-} __packed;
-
-struct gb_audio_dai {
- __u8 name[AUDIO_DAI_NAME_MAX];
- __le16 data_cport;
- struct gb_audio_pcm capture;
- struct gb_audio_pcm playback;
-} __packed;
-
-struct gb_audio_integer {
- __le32 min;
- __le32 max;
- __le32 step;
-} __packed;
-
-struct gb_audio_integer64 {
- __le64 min;
- __le64 max;
- __le64 step;
-} __packed;
-
-struct gb_audio_enumerated {
- __le32 items;
- __le16 names_length;
- __u8 names[0];
-} __packed;
-
-struct gb_audio_ctl_elem_info { /* See snd_ctl_elem_info in Linux source */
- __u8 type; /* GB_AUDIO_CTL_ELEM_TYPE_* */
- __le16 dimen[4];
- union {
- struct gb_audio_integer integer;
- struct gb_audio_integer64 integer64;
- struct gb_audio_enumerated enumerated;
- } value;
-} __packed;
-
-struct gb_audio_ctl_elem_value { /* See snd_ctl_elem_value in Linux source */
- __le64 timestamp; /* XXX needed? */
- union {
- __le32 integer_value[2]; /* consider CTL_DOUBLE_xxx */
- __le64 integer64_value[2];
- __le32 enumerated_item[2];
- } value;
-} __packed;
-
-struct gb_audio_control {
- __u8 name[AUDIO_CONTROL_NAME_MAX];
- __u8 id; /* 0-63 */
- __u8 iface; /* GB_AUDIO_IFACE_* */
- __le16 data_cport;
- __le32 access; /* GB_AUDIO_ACCESS_* */
- __u8 count; /* count of same elements */
- __u8 count_values; /* count of values, max=2 for CTL_DOUBLE_xxx */
- struct gb_audio_ctl_elem_info info;
-} __packed;
-
-struct gb_audio_widget {
- __u8 name[AUDIO_WIDGET_NAME_MAX];
- __u8 sname[AUDIO_WIDGET_NAME_MAX];
- __u8 id;
- __u8 type; /* GB_AUDIO_WIDGET_TYPE_* */
- __u8 state; /* GB_AUDIO_WIDGET_STATE_* */
- __u8 ncontrols;
- struct gb_audio_control ctl[0]; /* 'ncontrols' entries */
-} __packed;
-
-struct gb_audio_route {
- __u8 source_id; /* widget id */
- __u8 destination_id; /* widget id */
- __u8 control_id; /* 0-63 */
- __u8 index; /* Selection within the control */
-} __packed;
-
-struct gb_audio_topology {
- __u8 num_dais;
- __u8 num_controls;
- __u8 num_widgets;
- __u8 num_routes;
- __le32 size_dais;
- __le32 size_controls;
- __le32 size_widgets;
- __le32 size_routes;
- __le32 jack_type;
- /*
- * struct gb_audio_dai dai[num_dais];
- * struct gb_audio_control controls[num_controls];
- * struct gb_audio_widget widgets[num_widgets];
- * struct gb_audio_route routes[num_routes];
- */
- __u8 data[0];
-} __packed;
-
-struct gb_audio_get_topology_size_response {
- __le16 size;
-} __packed;
-
-struct gb_audio_get_topology_response {
- struct gb_audio_topology topology;
-} __packed;
-
-struct gb_audio_get_control_request {
- __u8 control_id;
- __u8 index;
-} __packed;
-
-struct gb_audio_get_control_response {
- struct gb_audio_ctl_elem_value value;
-} __packed;
-
-struct gb_audio_set_control_request {
- __u8 control_id;
- __u8 index;
- struct gb_audio_ctl_elem_value value;
-} __packed;
-
-struct gb_audio_enable_widget_request {
- __u8 widget_id;
-} __packed;
-
-struct gb_audio_disable_widget_request {
- __u8 widget_id;
-} __packed;
-
-struct gb_audio_get_pcm_request {
- __le16 data_cport;
-} __packed;
-
-struct gb_audio_get_pcm_response {
- __le32 format;
- __le32 rate;
- __u8 channels;
- __u8 sig_bits;
-} __packed;
-
-struct gb_audio_set_pcm_request {
- __le16 data_cport;
- __le32 format;
- __le32 rate;
- __u8 channels;
- __u8 sig_bits;
-} __packed;
-
-struct gb_audio_set_tx_data_size_request {
- __le16 data_cport;
- __le16 size;
-} __packed;
-
-struct gb_audio_activate_tx_request {
- __le16 data_cport;
-} __packed;
-
-struct gb_audio_deactivate_tx_request {
- __le16 data_cport;
-} __packed;
-
-struct gb_audio_set_rx_data_size_request {
- __le16 data_cport;
- __le16 size;
-} __packed;
-
-struct gb_audio_activate_rx_request {
- __le16 data_cport;
-} __packed;
-
-struct gb_audio_deactivate_rx_request {
- __le16 data_cport;
-} __packed;
-
-struct gb_audio_jack_event_request {
- __u8 widget_id;
- __u8 jack_attribute;
- __u8 event;
-} __packed;
-
-struct gb_audio_button_event_request {
- __u8 widget_id;
- __u8 button_id;
- __u8 event;
-} __packed;
-
-struct gb_audio_streaming_event_request {
- __le16 data_cport;
- __u8 event;
-} __packed;
-
-struct gb_audio_send_data_request {
- __le64 timestamp;
- __u8 data[0];
-} __packed;
-
-
-/* Log */
-
-/* operations */
-#define GB_LOG_TYPE_SEND_LOG 0x02
-
-/* length */
-#define GB_LOG_MAX_LEN 1024
-
-struct gb_log_send_log_request {
- __le16 len;
- __u8 msg[0];
-} __packed;
-
-#endif /* __GREYBUS_PROTOCOLS_H */
-
diff --git a/drivers/staging/greybus/greybus_trace.h b/drivers/staging/greybus/greybus_trace.h
deleted file mode 100644
index 7b5e2c6b1f6b..000000000000
--- a/drivers/staging/greybus/greybus_trace.h
+++ /dev/null
@@ -1,502 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus driver and device API
- *
- * Copyright 2015 Google Inc.
- * Copyright 2015 Linaro Ltd.
- */
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM greybus
-
-#if !defined(_TRACE_GREYBUS_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_GREYBUS_H
-
-#include <linux/tracepoint.h>
-
-struct gb_message;
-struct gb_operation;
-struct gb_connection;
-struct gb_bundle;
-struct gb_host_device;
-
-DECLARE_EVENT_CLASS(gb_message,
-
- TP_PROTO(struct gb_message *message),
-
- TP_ARGS(message),
-
- TP_STRUCT__entry(
- __field(u16, size)
- __field(u16, operation_id)
- __field(u8, type)
- __field(u8, result)
- ),
-
- TP_fast_assign(
- __entry->size = le16_to_cpu(message->header->size);
- __entry->operation_id =
- le16_to_cpu(message->header->operation_id);
- __entry->type = message->header->type;
- __entry->result = message->header->result;
- ),
-
- TP_printk("size=%hu operation_id=0x%04x type=0x%02x result=0x%02x",
- __entry->size, __entry->operation_id,
- __entry->type, __entry->result)
-);
-
-#define DEFINE_MESSAGE_EVENT(name) \
- DEFINE_EVENT(gb_message, name, \
- TP_PROTO(struct gb_message *message), \
- TP_ARGS(message))
-
-/*
- * Occurs immediately before calling a host device's message_send()
- * method.
- */
-DEFINE_MESSAGE_EVENT(gb_message_send);
-
-/*
- * Occurs after an incoming request message has been received
- */
-DEFINE_MESSAGE_EVENT(gb_message_recv_request);
-
-/*
- * Occurs after an incoming response message has been received,
- * after its matching request has been found.
- */
-DEFINE_MESSAGE_EVENT(gb_message_recv_response);
-
-/*
- * Occurs after an operation has been canceled, possibly before the
- * cancellation is complete.
- */
-DEFINE_MESSAGE_EVENT(gb_message_cancel_outgoing);
-
-/*
- * Occurs when an incoming request is cancelled; if the response has
- * been queued for sending, this occurs after it is sent.
- */
-DEFINE_MESSAGE_EVENT(gb_message_cancel_incoming);
-
-/*
- * Occurs in the host driver message_send() function just prior to
- * handing off the data to be processed by hardware.
- */
-DEFINE_MESSAGE_EVENT(gb_message_submit);
-
-#undef DEFINE_MESSAGE_EVENT
-
-DECLARE_EVENT_CLASS(gb_operation,
-
- TP_PROTO(struct gb_operation *operation),
-
- TP_ARGS(operation),
-
- TP_STRUCT__entry(
- __field(u16, cport_id) /* CPort of HD side of connection */
- __field(u16, id) /* Operation ID */
- __field(u8, type)
- __field(unsigned long, flags)
- __field(int, active)
- __field(int, waiters)
- __field(int, errno)
- ),
-
- TP_fast_assign(
- __entry->cport_id = operation->connection->hd_cport_id;
- __entry->id = operation->id;
- __entry->type = operation->type;
- __entry->flags = operation->flags;
- __entry->active = operation->active;
- __entry->waiters = atomic_read(&operation->waiters);
- __entry->errno = operation->errno;
- ),
-
- TP_printk("id=%04x type=0x%02x cport_id=%04x flags=0x%lx active=%d waiters=%d errno=%d",
- __entry->id, __entry->cport_id, __entry->type, __entry->flags,
- __entry->active, __entry->waiters, __entry->errno)
-);
-
-#define DEFINE_OPERATION_EVENT(name) \
- DEFINE_EVENT(gb_operation, name, \
- TP_PROTO(struct gb_operation *operation), \
- TP_ARGS(operation))
-
-/*
- * Occurs after a new operation is created for an outgoing request
- * has been successfully created.
- */
-DEFINE_OPERATION_EVENT(gb_operation_create);
-
-/*
- * Occurs after a new core operation has been created.
- */
-DEFINE_OPERATION_EVENT(gb_operation_create_core);
-
-/*
- * Occurs after a new operation has been created for an incoming
- * request has been successfully created and initialized.
- */
-DEFINE_OPERATION_EVENT(gb_operation_create_incoming);
-
-/*
- * Occurs when the last reference to an operation has been dropped,
- * prior to freeing resources.
- */
-DEFINE_OPERATION_EVENT(gb_operation_destroy);
-
-/*
- * Occurs when an operation has been marked active, after updating
- * its active count.
- */
-DEFINE_OPERATION_EVENT(gb_operation_get_active);
-
-/*
- * Occurs when an operation has been marked active, before updating
- * its active count.
- */
-DEFINE_OPERATION_EVENT(gb_operation_put_active);
-
-#undef DEFINE_OPERATION_EVENT
-
-DECLARE_EVENT_CLASS(gb_connection,
-
- TP_PROTO(struct gb_connection *connection),
-
- TP_ARGS(connection),
-
- TP_STRUCT__entry(
- __field(int, hd_bus_id)
- __field(u8, bundle_id)
- /* name contains "hd_cport_id/intf_id:cport_id" */
- __dynamic_array(char, name, sizeof(connection->name))
- __field(enum gb_connection_state, state)
- __field(unsigned long, flags)
- ),
-
- TP_fast_assign(
- __entry->hd_bus_id = connection->hd->bus_id;
- __entry->bundle_id = connection->bundle ?
- connection->bundle->id : BUNDLE_ID_NONE;
- memcpy(__get_str(name), connection->name,
- sizeof(connection->name));
- __entry->state = connection->state;
- __entry->flags = connection->flags;
- ),
-
- TP_printk("hd_bus_id=%d bundle_id=0x%02x name=\"%s\" state=%u flags=0x%lx",
- __entry->hd_bus_id, __entry->bundle_id, __get_str(name),
- (unsigned int)__entry->state, __entry->flags)
-);
-
-#define DEFINE_CONNECTION_EVENT(name) \
- DEFINE_EVENT(gb_connection, name, \
- TP_PROTO(struct gb_connection *connection), \
- TP_ARGS(connection))
-
-/*
- * Occurs after a new connection is successfully created.
- */
-DEFINE_CONNECTION_EVENT(gb_connection_create);
-
-/*
- * Occurs when the last reference to a connection has been dropped,
- * before its resources are freed.
- */
-DEFINE_CONNECTION_EVENT(gb_connection_release);
-
-/*
- * Occurs when a new reference to connection is added, currently
- * only when a message over the connection is received.
- */
-DEFINE_CONNECTION_EVENT(gb_connection_get);
-
-/*
- * Occurs when a new reference to connection is dropped, after a
- * a received message is handled, or when the connection is
- * destroyed.
- */
-DEFINE_CONNECTION_EVENT(gb_connection_put);
-
-/*
- * Occurs when a request to enable a connection is made, either for
- * transmit only, or for both transmit and receive.
- */
-DEFINE_CONNECTION_EVENT(gb_connection_enable);
-
-/*
- * Occurs when a request to disable a connection is made, either for
- * receive only, or for both transmit and receive. Also occurs when
- * a request to forcefully disable a connection is made.
- */
-DEFINE_CONNECTION_EVENT(gb_connection_disable);
-
-#undef DEFINE_CONNECTION_EVENT
-
-DECLARE_EVENT_CLASS(gb_bundle,
-
- TP_PROTO(struct gb_bundle *bundle),
-
- TP_ARGS(bundle),
-
- TP_STRUCT__entry(
- __field(u8, intf_id)
- __field(u8, id)
- __field(u8, class)
- __field(size_t, num_cports)
- ),
-
- TP_fast_assign(
- __entry->intf_id = bundle->intf->interface_id;
- __entry->id = bundle->id;
- __entry->class = bundle->class;
- __entry->num_cports = bundle->num_cports;
- ),
-
- TP_printk("intf_id=0x%02x id=%02x class=0x%02x num_cports=%zu",
- __entry->intf_id, __entry->id, __entry->class,
- __entry->num_cports)
-);
-
-#define DEFINE_BUNDLE_EVENT(name) \
- DEFINE_EVENT(gb_bundle, name, \
- TP_PROTO(struct gb_bundle *bundle), \
- TP_ARGS(bundle))
-
-/*
- * Occurs after a new bundle is successfully created.
- */
-DEFINE_BUNDLE_EVENT(gb_bundle_create);
-
-/*
- * Occurs when the last reference to a bundle has been dropped,
- * before its resources are freed.
- */
-DEFINE_BUNDLE_EVENT(gb_bundle_release);
-
-/*
- * Occurs when a bundle is added to an interface when the interface
- * is enabled.
- */
-DEFINE_BUNDLE_EVENT(gb_bundle_add);
-
-/*
- * Occurs when a registered bundle gets destroyed, normally at the
- * time an interface is disabled.
- */
-DEFINE_BUNDLE_EVENT(gb_bundle_destroy);
-
-#undef DEFINE_BUNDLE_EVENT
-
-DECLARE_EVENT_CLASS(gb_interface,
-
- TP_PROTO(struct gb_interface *intf),
-
- TP_ARGS(intf),
-
- TP_STRUCT__entry(
- __field(u8, module_id)
- __field(u8, id) /* Interface id */
- __field(u8, device_id)
- __field(int, disconnected) /* bool */
- __field(int, ejected) /* bool */
- __field(int, active) /* bool */
- __field(int, enabled) /* bool */
- __field(int, mode_switch) /* bool */
- ),
-
- TP_fast_assign(
- __entry->module_id = intf->module->module_id;
- __entry->id = intf->interface_id;
- __entry->device_id = intf->device_id;
- __entry->disconnected = intf->disconnected;
- __entry->ejected = intf->ejected;
- __entry->active = intf->active;
- __entry->enabled = intf->enabled;
- __entry->mode_switch = intf->mode_switch;
- ),
-
- TP_printk("intf_id=%hhu device_id=%hhu module_id=%hhu D=%d J=%d A=%d E=%d M=%d",
- __entry->id, __entry->device_id, __entry->module_id,
- __entry->disconnected, __entry->ejected, __entry->active,
- __entry->enabled, __entry->mode_switch)
-);
-
-#define DEFINE_INTERFACE_EVENT(name) \
- DEFINE_EVENT(gb_interface, name, \
- TP_PROTO(struct gb_interface *intf), \
- TP_ARGS(intf))
-
-/*
- * Occurs after a new interface is successfully created.
- */
-DEFINE_INTERFACE_EVENT(gb_interface_create);
-
-/*
- * Occurs after the last reference to an interface has been dropped.
- */
-DEFINE_INTERFACE_EVENT(gb_interface_release);
-
-/*
- * Occurs after an interface been registerd.
- */
-DEFINE_INTERFACE_EVENT(gb_interface_add);
-
-/*
- * Occurs when a registered interface gets deregisterd.
- */
-DEFINE_INTERFACE_EVENT(gb_interface_del);
-
-/*
- * Occurs when a registered interface has been successfully
- * activated.
- */
-DEFINE_INTERFACE_EVENT(gb_interface_activate);
-
-/*
- * Occurs when an activated interface is being deactivated.
- */
-DEFINE_INTERFACE_EVENT(gb_interface_deactivate);
-
-/*
- * Occurs when an interface has been successfully enabled.
- */
-DEFINE_INTERFACE_EVENT(gb_interface_enable);
-
-/*
- * Occurs when an enabled interface is being disabled.
- */
-DEFINE_INTERFACE_EVENT(gb_interface_disable);
-
-#undef DEFINE_INTERFACE_EVENT
-
-DECLARE_EVENT_CLASS(gb_module,
-
- TP_PROTO(struct gb_module *module),
-
- TP_ARGS(module),
-
- TP_STRUCT__entry(
- __field(int, hd_bus_id)
- __field(u8, module_id)
- __field(size_t, num_interfaces)
- __field(int, disconnected) /* bool */
- ),
-
- TP_fast_assign(
- __entry->hd_bus_id = module->hd->bus_id;
- __entry->module_id = module->module_id;
- __entry->num_interfaces = module->num_interfaces;
- __entry->disconnected = module->disconnected;
- ),
-
- TP_printk("hd_bus_id=%d module_id=%hhu num_interfaces=%zu disconnected=%d",
- __entry->hd_bus_id, __entry->module_id,
- __entry->num_interfaces, __entry->disconnected)
-);
-
-#define DEFINE_MODULE_EVENT(name) \
- DEFINE_EVENT(gb_module, name, \
- TP_PROTO(struct gb_module *module), \
- TP_ARGS(module))
-
-/*
- * Occurs after a new module is successfully created, before
- * creating any of its interfaces.
- */
-DEFINE_MODULE_EVENT(gb_module_create);
-
-/*
- * Occurs after the last reference to a module has been dropped.
- */
-DEFINE_MODULE_EVENT(gb_module_release);
-
-/*
- * Occurs after a module is successfully created, before registering
- * any of its interfaces.
- */
-DEFINE_MODULE_EVENT(gb_module_add);
-
-/*
- * Occurs when a module is deleted, before deregistering its
- * interfaces.
- */
-DEFINE_MODULE_EVENT(gb_module_del);
-
-#undef DEFINE_MODULE_EVENT
-
-DECLARE_EVENT_CLASS(gb_host_device,
-
- TP_PROTO(struct gb_host_device *hd),
-
- TP_ARGS(hd),
-
- TP_STRUCT__entry(
- __field(int, bus_id)
- __field(size_t, num_cports)
- __field(size_t, buffer_size_max)
- ),
-
- TP_fast_assign(
- __entry->bus_id = hd->bus_id;
- __entry->num_cports = hd->num_cports;
- __entry->buffer_size_max = hd->buffer_size_max;
- ),
-
- TP_printk("bus_id=%d num_cports=%zu mtu=%zu",
- __entry->bus_id, __entry->num_cports,
- __entry->buffer_size_max)
-);
-
-#define DEFINE_HD_EVENT(name) \
- DEFINE_EVENT(gb_host_device, name, \
- TP_PROTO(struct gb_host_device *hd), \
- TP_ARGS(hd))
-
-/*
- * Occurs after a new host device is successfully created, before
- * its SVC has been set up.
- */
-DEFINE_HD_EVENT(gb_hd_create);
-
-/*
- * Occurs after the last reference to a host device has been
- * dropped.
- */
-DEFINE_HD_EVENT(gb_hd_release);
-
-/*
- * Occurs after a new host device has been added, after the
- * connection to its SVC has been enabled.
- */
-DEFINE_HD_EVENT(gb_hd_add);
-
-/*
- * Occurs when a host device is being disconnected from the AP USB
- * host controller.
- */
-DEFINE_HD_EVENT(gb_hd_del);
-
-/*
- * Occurs when a host device has passed received data to the Greybus
- * core, after it has been determined it is destined for a valid
- * CPort.
- */
-DEFINE_HD_EVENT(gb_hd_in);
-
-#undef DEFINE_HD_EVENT
-
-#endif /* _TRACE_GREYBUS_H */
-
-/* This part must be outside protection */
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-
-/*
- * TRACE_INCLUDE_FILE is not needed if the filename and TRACE_SYSTEM are equal
- */
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_FILE greybus_trace
-#include <trace/define_trace.h>
-
diff --git a/drivers/staging/greybus/hd.c b/drivers/staging/greybus/hd.c
deleted file mode 100644
index 969f86697673..000000000000
--- a/drivers/staging/greybus/hd.c
+++ /dev/null
@@ -1,256 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus Host Device
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include "greybus.h"
-#include "greybus_trace.h"
-
-EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_create);
-EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_release);
-EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_add);
-EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_del);
-EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_in);
-EXPORT_TRACEPOINT_SYMBOL_GPL(gb_message_submit);
-
-static struct ida gb_hd_bus_id_map;
-
-int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
- bool async)
-{
- if (!hd || !hd->driver || !hd->driver->output)
- return -EINVAL;
- return hd->driver->output(hd, req, size, cmd, async);
-}
-EXPORT_SYMBOL_GPL(gb_hd_output);
-
-static ssize_t bus_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_host_device *hd = to_gb_host_device(dev);
-
- return sprintf(buf, "%d\n", hd->bus_id);
-}
-static DEVICE_ATTR_RO(bus_id);
-
-static struct attribute *bus_attrs[] = {
- &dev_attr_bus_id.attr,
- NULL
-};
-ATTRIBUTE_GROUPS(bus);
-
-int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id)
-{
- struct ida *id_map = &hd->cport_id_map;
- int ret;
-
- ret = ida_simple_get(id_map, cport_id, cport_id + 1, GFP_KERNEL);
- if (ret < 0) {
- dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id);
- return ret;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(gb_hd_cport_reserve);
-
-void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id)
-{
- struct ida *id_map = &hd->cport_id_map;
-
- ida_simple_remove(id_map, cport_id);
-}
-EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved);
-
-/* Locking: Caller guarantees serialisation */
-int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id,
- unsigned long flags)
-{
- struct ida *id_map = &hd->cport_id_map;
- int ida_start, ida_end;
-
- if (hd->driver->cport_allocate)
- return hd->driver->cport_allocate(hd, cport_id, flags);
-
- if (cport_id < 0) {
- ida_start = 0;
- ida_end = hd->num_cports;
- } else if (cport_id < hd->num_cports) {
- ida_start = cport_id;
- ida_end = cport_id + 1;
- } else {
- dev_err(&hd->dev, "cport %d not available\n", cport_id);
- return -EINVAL;
- }
-
- return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
-}
-
-/* Locking: Caller guarantees serialisation */
-void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id)
-{
- if (hd->driver->cport_release) {
- hd->driver->cport_release(hd, cport_id);
- return;
- }
-
- ida_simple_remove(&hd->cport_id_map, cport_id);
-}
-
-static void gb_hd_release(struct device *dev)
-{
- struct gb_host_device *hd = to_gb_host_device(dev);
-
- trace_gb_hd_release(hd);
-
- if (hd->svc)
- gb_svc_put(hd->svc);
- ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id);
- ida_destroy(&hd->cport_id_map);
- kfree(hd);
-}
-
-struct device_type greybus_hd_type = {
- .name = "greybus_host_device",
- .release = gb_hd_release,
-};
-
-struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
- struct device *parent,
- size_t buffer_size_max,
- size_t num_cports)
-{
- struct gb_host_device *hd;
- int ret;
-
- /*
- * Validate that the driver implements all of the callbacks
- * so that we don't have to every time we make them.
- */
- if ((!driver->message_send) || (!driver->message_cancel)) {
- dev_err(parent, "mandatory hd-callbacks missing\n");
- return ERR_PTR(-EINVAL);
- }
-
- if (buffer_size_max < GB_OPERATION_MESSAGE_SIZE_MIN) {
- dev_err(parent, "greybus host-device buffers too small\n");
- return ERR_PTR(-EINVAL);
- }
-
- if (num_cports == 0 || num_cports > CPORT_ID_MAX + 1) {
- dev_err(parent, "Invalid number of CPorts: %zu\n", num_cports);
- return ERR_PTR(-EINVAL);
- }
-
- /*
- * Make sure to never allocate messages larger than what the Greybus
- * protocol supports.
- */
- if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) {
- dev_warn(parent, "limiting buffer size to %u\n",
- GB_OPERATION_MESSAGE_SIZE_MAX);
- buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
- }
-
- hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
- if (!hd)
- return ERR_PTR(-ENOMEM);
-
- ret = ida_simple_get(&gb_hd_bus_id_map, 1, 0, GFP_KERNEL);
- if (ret < 0) {
- kfree(hd);
- return ERR_PTR(ret);
- }
- hd->bus_id = ret;
-
- hd->driver = driver;
- INIT_LIST_HEAD(&hd->modules);
- INIT_LIST_HEAD(&hd->connections);
- ida_init(&hd->cport_id_map);
- hd->buffer_size_max = buffer_size_max;
- hd->num_cports = num_cports;
-
- hd->dev.parent = parent;
- hd->dev.bus = &greybus_bus_type;
- hd->dev.type = &greybus_hd_type;
- hd->dev.groups = bus_groups;
- hd->dev.dma_mask = hd->dev.parent->dma_mask;
- device_initialize(&hd->dev);
- dev_set_name(&hd->dev, "greybus%d", hd->bus_id);
-
- trace_gb_hd_create(hd);
-
- hd->svc = gb_svc_create(hd);
- if (!hd->svc) {
- dev_err(&hd->dev, "failed to create svc\n");
- put_device(&hd->dev);
- return ERR_PTR(-ENOMEM);
- }
-
- return hd;
-}
-EXPORT_SYMBOL_GPL(gb_hd_create);
-
-int gb_hd_add(struct gb_host_device *hd)
-{
- int ret;
-
- ret = device_add(&hd->dev);
- if (ret)
- return ret;
-
- ret = gb_svc_add(hd->svc);
- if (ret) {
- device_del(&hd->dev);
- return ret;
- }
-
- trace_gb_hd_add(hd);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(gb_hd_add);
-
-void gb_hd_del(struct gb_host_device *hd)
-{
- trace_gb_hd_del(hd);
-
- /*
- * Tear down the svc and flush any on-going hotplug processing before
- * removing the remaining interfaces.
- */
- gb_svc_del(hd->svc);
-
- device_del(&hd->dev);
-}
-EXPORT_SYMBOL_GPL(gb_hd_del);
-
-void gb_hd_shutdown(struct gb_host_device *hd)
-{
- gb_svc_del(hd->svc);
-}
-EXPORT_SYMBOL_GPL(gb_hd_shutdown);
-
-void gb_hd_put(struct gb_host_device *hd)
-{
- put_device(&hd->dev);
-}
-EXPORT_SYMBOL_GPL(gb_hd_put);
-
-int __init gb_hd_init(void)
-{
- ida_init(&gb_hd_bus_id_map);
-
- return 0;
-}
-
-void gb_hd_exit(void)
-{
- ida_destroy(&gb_hd_bus_id_map);
-}
diff --git a/drivers/staging/greybus/hd.h b/drivers/staging/greybus/hd.h
deleted file mode 100644
index 6cf024a20a58..000000000000
--- a/drivers/staging/greybus/hd.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus Host Device
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- */
-
-#ifndef __HD_H
-#define __HD_H
-
-struct gb_host_device;
-struct gb_message;
-
-struct gb_hd_driver {
- size_t hd_priv_size;
-
- int (*cport_allocate)(struct gb_host_device *hd, int cport_id,
- unsigned long flags);
- void (*cport_release)(struct gb_host_device *hd, u16 cport_id);
- int (*cport_enable)(struct gb_host_device *hd, u16 cport_id,
- unsigned long flags);
- int (*cport_disable)(struct gb_host_device *hd, u16 cport_id);
- int (*cport_connected)(struct gb_host_device *hd, u16 cport_id);
- int (*cport_flush)(struct gb_host_device *hd, u16 cport_id);
- int (*cport_shutdown)(struct gb_host_device *hd, u16 cport_id,
- u8 phase, unsigned int timeout);
- int (*cport_quiesce)(struct gb_host_device *hd, u16 cport_id,
- size_t peer_space, unsigned int timeout);
- int (*cport_clear)(struct gb_host_device *hd, u16 cport_id);
-
- int (*message_send)(struct gb_host_device *hd, u16 dest_cport_id,
- struct gb_message *message, gfp_t gfp_mask);
- void (*message_cancel)(struct gb_message *message);
- int (*latency_tag_enable)(struct gb_host_device *hd, u16 cport_id);
- int (*latency_tag_disable)(struct gb_host_device *hd, u16 cport_id);
- int (*output)(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
- bool async);
-};
-
-struct gb_host_device {
- struct device dev;
- int bus_id;
- const struct gb_hd_driver *driver;
-
- struct list_head modules;
- struct list_head connections;
- struct ida cport_id_map;
-
- /* Number of CPorts supported by the UniPro IP */
- size_t num_cports;
-
- /* Host device buffer constraints */
- size_t buffer_size_max;
-
- struct gb_svc *svc;
- /* Private data for the host driver */
- unsigned long hd_priv[0] __aligned(sizeof(s64));
-};
-#define to_gb_host_device(d) container_of(d, struct gb_host_device, dev)
-
-int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id);
-void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id);
-int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id,
- unsigned long flags);
-void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id);
-
-struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
- struct device *parent,
- size_t buffer_size_max,
- size_t num_cports);
-int gb_hd_add(struct gb_host_device *hd);
-void gb_hd_del(struct gb_host_device *hd);
-void gb_hd_shutdown(struct gb_host_device *hd);
-void gb_hd_put(struct gb_host_device *hd);
-int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
- bool in_irq);
-
-int gb_hd_init(void);
-void gb_hd_exit(void);
-
-#endif /* __HD_H */
diff --git a/drivers/staging/greybus/hid.c b/drivers/staging/greybus/hid.c
index 8ab810bf5716..04bfd9110502 100644
--- a/drivers/staging/greybus/hid.c
+++ b/drivers/staging/greybus/hid.c
@@ -12,8 +12,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-
-#include "greybus.h"
+#include <linux/greybus.h>
/* Greybus HID device's structure */
struct gb_hid {
diff --git a/drivers/staging/greybus/i2c.c b/drivers/staging/greybus/i2c.c
index 7bb85a75d3b1..ab06fc3b9e7e 100644
--- a/drivers/staging/greybus/i2c.c
+++ b/drivers/staging/greybus/i2c.c
@@ -10,8 +10,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "gbphy.h"
struct gb_i2c_device {
@@ -31,7 +31,14 @@ static u32 gb_i2c_functionality_map(u32 gb_i2c_functionality)
return gb_i2c_functionality; /* All bits the same for now */
}
-static int gb_i2c_functionality_operation(struct gb_i2c_device *gb_i2c_dev)
+/*
+ * Do initial setup of the i2c device. This includes verifying we
+ * can support it (based on the protocol version it advertises).
+ * If that's OK, we get and cached its functionality bits.
+ *
+ * Note: gb_i2c_dev->connection is assumed to have been valid.
+ */
+static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev)
{
struct gb_i2c_functionality_response response;
u32 functionality;
@@ -235,19 +242,6 @@ static const struct i2c_algorithm gb_i2c_algorithm = {
.functionality = gb_i2c_functionality,
};
-/*
- * Do initial setup of the i2c device. This includes verifying we
- * can support it (based on the protocol version it advertises).
- * If that's OK, we get and cached its functionality bits.
- *
- * Note: gb_i2c_dev->connection is assumed to have been valid.
- */
-static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev)
-{
- /* Assume the functionality never changes, just get it once */
- return gb_i2c_functionality_operation(gb_i2c_dev);
-}
-
static int gb_i2c_probe(struct gbphy_device *gbphy_dev,
const struct gbphy_device_id *id)
{
diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c
deleted file mode 100644
index d7b5b89a2f40..000000000000
--- a/drivers/staging/greybus/interface.c
+++ /dev/null
@@ -1,1263 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus interface code
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- */
-
-#include <linux/delay.h>
-
-#include "greybus.h"
-#include "greybus_trace.h"
-
-#define GB_INTERFACE_MODE_SWITCH_TIMEOUT 2000
-
-#define GB_INTERFACE_DEVICE_ID_BAD 0xff
-
-#define GB_INTERFACE_AUTOSUSPEND_MS 3000
-
-/* Time required for interface to enter standby before disabling REFCLK */
-#define GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS 20
-
-/* Don't-care selector index */
-#define DME_SELECTOR_INDEX_NULL 0
-
-/* DME attributes */
-/* FIXME: remove ES2 support and DME_T_TST_SRC_INCREMENT */
-#define DME_T_TST_SRC_INCREMENT 0x4083
-
-#define DME_DDBL1_MANUFACTURERID 0x5003
-#define DME_DDBL1_PRODUCTID 0x5004
-
-#define DME_TOSHIBA_GMP_VID 0x6000
-#define DME_TOSHIBA_GMP_PID 0x6001
-#define DME_TOSHIBA_GMP_SN0 0x6002
-#define DME_TOSHIBA_GMP_SN1 0x6003
-#define DME_TOSHIBA_GMP_INIT_STATUS 0x6101
-
-/* DDBL1 Manufacturer and Product ids */
-#define TOSHIBA_DMID 0x0126
-#define TOSHIBA_ES2_BRIDGE_DPID 0x1000
-#define TOSHIBA_ES3_APBRIDGE_DPID 0x1001
-#define TOSHIBA_ES3_GBPHY_DPID 0x1002
-
-static int gb_interface_hibernate_link(struct gb_interface *intf);
-static int gb_interface_refclk_set(struct gb_interface *intf, bool enable);
-
-static int gb_interface_dme_attr_get(struct gb_interface *intf,
- u16 attr, u32 *val)
-{
- return gb_svc_dme_peer_get(intf->hd->svc, intf->interface_id,
- attr, DME_SELECTOR_INDEX_NULL, val);
-}
-
-static int gb_interface_read_ara_dme(struct gb_interface *intf)
-{
- u32 sn0, sn1;
- int ret;
-
- /*
- * Unless this is a Toshiba bridge, bail out until we have defined
- * standard GMP attributes.
- */
- if (intf->ddbl1_manufacturer_id != TOSHIBA_DMID) {
- dev_err(&intf->dev, "unknown manufacturer %08x\n",
- intf->ddbl1_manufacturer_id);
- return -ENODEV;
- }
-
- ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_VID,
- &intf->vendor_id);
- if (ret)
- return ret;
-
- ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_PID,
- &intf->product_id);
- if (ret)
- return ret;
-
- ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN0, &sn0);
- if (ret)
- return ret;
-
- ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN1, &sn1);
- if (ret)
- return ret;
-
- intf->serial_number = (u64)sn1 << 32 | sn0;
-
- return 0;
-}
-
-static int gb_interface_read_dme(struct gb_interface *intf)
-{
- int ret;
-
- /* DME attributes have already been read */
- if (intf->dme_read)
- return 0;
-
- ret = gb_interface_dme_attr_get(intf, DME_DDBL1_MANUFACTURERID,
- &intf->ddbl1_manufacturer_id);
- if (ret)
- return ret;
-
- ret = gb_interface_dme_attr_get(intf, DME_DDBL1_PRODUCTID,
- &intf->ddbl1_product_id);
- if (ret)
- return ret;
-
- if (intf->ddbl1_manufacturer_id == TOSHIBA_DMID &&
- intf->ddbl1_product_id == TOSHIBA_ES2_BRIDGE_DPID) {
- intf->quirks |= GB_INTERFACE_QUIRK_NO_GMP_IDS;
- intf->quirks |= GB_INTERFACE_QUIRK_NO_INIT_STATUS;
- }
-
- ret = gb_interface_read_ara_dme(intf);
- if (ret)
- return ret;
-
- intf->dme_read = true;
-
- return 0;
-}
-
-static int gb_interface_route_create(struct gb_interface *intf)
-{
- struct gb_svc *svc = intf->hd->svc;
- u8 intf_id = intf->interface_id;
- u8 device_id;
- int ret;
-
- /* Allocate an interface device id. */
- ret = ida_simple_get(&svc->device_id_map,
- GB_SVC_DEVICE_ID_MIN, GB_SVC_DEVICE_ID_MAX + 1,
- GFP_KERNEL);
- if (ret < 0) {
- dev_err(&intf->dev, "failed to allocate device id: %d\n", ret);
- return ret;
- }
- device_id = ret;
-
- ret = gb_svc_intf_device_id(svc, intf_id, device_id);
- if (ret) {
- dev_err(&intf->dev, "failed to set device id %u: %d\n",
- device_id, ret);
- goto err_ida_remove;
- }
-
- /* FIXME: Hard-coded AP device id. */
- ret = gb_svc_route_create(svc, svc->ap_intf_id, GB_SVC_DEVICE_ID_AP,
- intf_id, device_id);
- if (ret) {
- dev_err(&intf->dev, "failed to create route: %d\n", ret);
- goto err_svc_id_free;
- }
-
- intf->device_id = device_id;
-
- return 0;
-
-err_svc_id_free:
- /*
- * XXX Should we tell SVC that this id doesn't belong to interface
- * XXX anymore.
- */
-err_ida_remove:
- ida_simple_remove(&svc->device_id_map, device_id);
-
- return ret;
-}
-
-static void gb_interface_route_destroy(struct gb_interface *intf)
-{
- struct gb_svc *svc = intf->hd->svc;
-
- if (intf->device_id == GB_INTERFACE_DEVICE_ID_BAD)
- return;
-
- gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id);
- ida_simple_remove(&svc->device_id_map, intf->device_id);
- intf->device_id = GB_INTERFACE_DEVICE_ID_BAD;
-}
-
-/* Locking: Caller holds the interface mutex. */
-static int gb_interface_legacy_mode_switch(struct gb_interface *intf)
-{
- int ret;
-
- dev_info(&intf->dev, "legacy mode switch detected\n");
-
- /* Mark as disconnected to prevent I/O during disable. */
- intf->disconnected = true;
- gb_interface_disable(intf);
- intf->disconnected = false;
-
- ret = gb_interface_enable(intf);
- if (ret) {
- dev_err(&intf->dev, "failed to re-enable interface: %d\n", ret);
- gb_interface_deactivate(intf);
- }
-
- return ret;
-}
-
-void gb_interface_mailbox_event(struct gb_interface *intf, u16 result,
- u32 mailbox)
-{
- mutex_lock(&intf->mutex);
-
- if (result) {
- dev_warn(&intf->dev,
- "mailbox event with UniPro error: 0x%04x\n",
- result);
- goto err_disable;
- }
-
- if (mailbox != GB_SVC_INTF_MAILBOX_GREYBUS) {
- dev_warn(&intf->dev,
- "mailbox event with unexpected value: 0x%08x\n",
- mailbox);
- goto err_disable;
- }
-
- if (intf->quirks & GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH) {
- gb_interface_legacy_mode_switch(intf);
- goto out_unlock;
- }
-
- if (!intf->mode_switch) {
- dev_warn(&intf->dev, "unexpected mailbox event: 0x%08x\n",
- mailbox);
- goto err_disable;
- }
-
- dev_info(&intf->dev, "mode switch detected\n");
-
- complete(&intf->mode_switch_completion);
-
-out_unlock:
- mutex_unlock(&intf->mutex);
-
- return;
-
-err_disable:
- gb_interface_disable(intf);
- gb_interface_deactivate(intf);
- mutex_unlock(&intf->mutex);
-}
-
-static void gb_interface_mode_switch_work(struct work_struct *work)
-{
- struct gb_interface *intf;
- struct gb_control *control;
- unsigned long timeout;
- int ret;
-
- intf = container_of(work, struct gb_interface, mode_switch_work);
-
- mutex_lock(&intf->mutex);
- /* Make sure interface is still enabled. */
- if (!intf->enabled) {
- dev_dbg(&intf->dev, "mode switch aborted\n");
- intf->mode_switch = false;
- mutex_unlock(&intf->mutex);
- goto out_interface_put;
- }
-
- /*
- * Prepare the control device for mode switch and make sure to get an
- * extra reference before it goes away during interface disable.
- */
- control = gb_control_get(intf->control);
- gb_control_mode_switch_prepare(control);
- gb_interface_disable(intf);
- mutex_unlock(&intf->mutex);
-
- timeout = msecs_to_jiffies(GB_INTERFACE_MODE_SWITCH_TIMEOUT);
- ret = wait_for_completion_interruptible_timeout(
- &intf->mode_switch_completion, timeout);
-
- /* Finalise control-connection mode switch. */
- gb_control_mode_switch_complete(control);
- gb_control_put(control);
-
- if (ret < 0) {
- dev_err(&intf->dev, "mode switch interrupted\n");
- goto err_deactivate;
- } else if (ret == 0) {
- dev_err(&intf->dev, "mode switch timed out\n");
- goto err_deactivate;
- }
-
- /* Re-enable (re-enumerate) interface if still active. */
- mutex_lock(&intf->mutex);
- intf->mode_switch = false;
- if (intf->active) {
- ret = gb_interface_enable(intf);
- if (ret) {
- dev_err(&intf->dev, "failed to re-enable interface: %d\n",
- ret);
- gb_interface_deactivate(intf);
- }
- }
- mutex_unlock(&intf->mutex);
-
-out_interface_put:
- gb_interface_put(intf);
-
- return;
-
-err_deactivate:
- mutex_lock(&intf->mutex);
- intf->mode_switch = false;
- gb_interface_deactivate(intf);
- mutex_unlock(&intf->mutex);
-
- gb_interface_put(intf);
-}
-
-int gb_interface_request_mode_switch(struct gb_interface *intf)
-{
- int ret = 0;
-
- mutex_lock(&intf->mutex);
- if (intf->mode_switch) {
- ret = -EBUSY;
- goto out_unlock;
- }
-
- intf->mode_switch = true;
- reinit_completion(&intf->mode_switch_completion);
-
- /*
- * Get a reference to the interface device, which will be put once the
- * mode switch is complete.
- */
- get_device(&intf->dev);
-
- if (!queue_work(system_long_wq, &intf->mode_switch_work)) {
- put_device(&intf->dev);
- ret = -EBUSY;
- goto out_unlock;
- }
-
-out_unlock:
- mutex_unlock(&intf->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_interface_request_mode_switch);
-
-/*
- * T_TstSrcIncrement is written by the module on ES2 as a stand-in for the
- * init-status attribute DME_TOSHIBA_INIT_STATUS. The AP needs to read and
- * clear it after reading a non-zero value from it.
- *
- * FIXME: This is module-hardware dependent and needs to be extended for every
- * type of module we want to support.
- */
-static int gb_interface_read_and_clear_init_status(struct gb_interface *intf)
-{
- struct gb_host_device *hd = intf->hd;
- unsigned long bootrom_quirks;
- unsigned long s2l_quirks;
- int ret;
- u32 value;
- u16 attr;
- u8 init_status;
-
- /*
- * ES2 bridges use T_TstSrcIncrement for the init status.
- *
- * FIXME: Remove ES2 support
- */
- if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS)
- attr = DME_T_TST_SRC_INCREMENT;
- else
- attr = DME_TOSHIBA_GMP_INIT_STATUS;
-
- ret = gb_svc_dme_peer_get(hd->svc, intf->interface_id, attr,
- DME_SELECTOR_INDEX_NULL, &value);
- if (ret)
- return ret;
-
- /*
- * A nonzero init status indicates the module has finished
- * initializing.
- */
- if (!value) {
- dev_err(&intf->dev, "invalid init status\n");
- return -ENODEV;
- }
-
- /*
- * Extract the init status.
- *
- * For ES2: We need to check lowest 8 bits of 'value'.
- * For ES3: We need to check highest 8 bits out of 32 of 'value'.
- *
- * FIXME: Remove ES2 support
- */
- if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS)
- init_status = value & 0xff;
- else
- init_status = value >> 24;
-
- /*
- * Check if the interface is executing the quirky ES3 bootrom that,
- * for example, requires E2EFC, CSD and CSV to be disabled.
- */
- bootrom_quirks = GB_INTERFACE_QUIRK_NO_CPORT_FEATURES |
- GB_INTERFACE_QUIRK_FORCED_DISABLE |
- GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH |
- GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE;
-
- s2l_quirks = GB_INTERFACE_QUIRK_NO_PM;
-
- switch (init_status) {
- case GB_INIT_BOOTROM_UNIPRO_BOOT_STARTED:
- case GB_INIT_BOOTROM_FALLBACK_UNIPRO_BOOT_STARTED:
- intf->quirks |= bootrom_quirks;
- break;
- case GB_INIT_S2_LOADER_BOOT_STARTED:
- /* S2 Loader doesn't support runtime PM */
- intf->quirks &= ~bootrom_quirks;
- intf->quirks |= s2l_quirks;
- break;
- default:
- intf->quirks &= ~bootrom_quirks;
- intf->quirks &= ~s2l_quirks;
- }
-
- /* Clear the init status. */
- return gb_svc_dme_peer_set(hd->svc, intf->interface_id, attr,
- DME_SELECTOR_INDEX_NULL, 0);
-}
-
-/* interface sysfs attributes */
-#define gb_interface_attr(field, type) \
-static ssize_t field##_show(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct gb_interface *intf = to_gb_interface(dev); \
- return scnprintf(buf, PAGE_SIZE, type"\n", intf->field); \
-} \
-static DEVICE_ATTR_RO(field)
-
-gb_interface_attr(ddbl1_manufacturer_id, "0x%08x");
-gb_interface_attr(ddbl1_product_id, "0x%08x");
-gb_interface_attr(interface_id, "%u");
-gb_interface_attr(vendor_id, "0x%08x");
-gb_interface_attr(product_id, "0x%08x");
-gb_interface_attr(serial_number, "0x%016llx");
-
-static ssize_t voltage_now_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_interface *intf = to_gb_interface(dev);
- int ret;
- u32 measurement;
-
- ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
- GB_SVC_PWRMON_TYPE_VOL,
- &measurement);
- if (ret) {
- dev_err(&intf->dev, "failed to get voltage sample (%d)\n", ret);
- return ret;
- }
-
- return sprintf(buf, "%u\n", measurement);
-}
-static DEVICE_ATTR_RO(voltage_now);
-
-static ssize_t current_now_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_interface *intf = to_gb_interface(dev);
- int ret;
- u32 measurement;
-
- ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
- GB_SVC_PWRMON_TYPE_CURR,
- &measurement);
- if (ret) {
- dev_err(&intf->dev, "failed to get current sample (%d)\n", ret);
- return ret;
- }
-
- return sprintf(buf, "%u\n", measurement);
-}
-static DEVICE_ATTR_RO(current_now);
-
-static ssize_t power_now_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_interface *intf = to_gb_interface(dev);
- int ret;
- u32 measurement;
-
- ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
- GB_SVC_PWRMON_TYPE_PWR,
- &measurement);
- if (ret) {
- dev_err(&intf->dev, "failed to get power sample (%d)\n", ret);
- return ret;
- }
-
- return sprintf(buf, "%u\n", measurement);
-}
-static DEVICE_ATTR_RO(power_now);
-
-static ssize_t power_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_interface *intf = to_gb_interface(dev);
-
- if (intf->active)
- return scnprintf(buf, PAGE_SIZE, "on\n");
- else
- return scnprintf(buf, PAGE_SIZE, "off\n");
-}
-
-static ssize_t power_state_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t len)
-{
- struct gb_interface *intf = to_gb_interface(dev);
- bool activate;
- int ret = 0;
-
- if (kstrtobool(buf, &activate))
- return -EINVAL;
-
- mutex_lock(&intf->mutex);
-
- if (activate == intf->active)
- goto unlock;
-
- if (activate) {
- ret = gb_interface_activate(intf);
- if (ret) {
- dev_err(&intf->dev,
- "failed to activate interface: %d\n", ret);
- goto unlock;
- }
-
- ret = gb_interface_enable(intf);
- if (ret) {
- dev_err(&intf->dev,
- "failed to enable interface: %d\n", ret);
- gb_interface_deactivate(intf);
- goto unlock;
- }
- } else {
- gb_interface_disable(intf);
- gb_interface_deactivate(intf);
- }
-
-unlock:
- mutex_unlock(&intf->mutex);
-
- if (ret)
- return ret;
-
- return len;
-}
-static DEVICE_ATTR_RW(power_state);
-
-static const char *gb_interface_type_string(struct gb_interface *intf)
-{
- static const char * const types[] = {
- [GB_INTERFACE_TYPE_INVALID] = "invalid",
- [GB_INTERFACE_TYPE_UNKNOWN] = "unknown",
- [GB_INTERFACE_TYPE_DUMMY] = "dummy",
- [GB_INTERFACE_TYPE_UNIPRO] = "unipro",
- [GB_INTERFACE_TYPE_GREYBUS] = "greybus",
- };
-
- return types[intf->type];
-}
-
-static ssize_t interface_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_interface *intf = to_gb_interface(dev);
-
- return sprintf(buf, "%s\n", gb_interface_type_string(intf));
-}
-static DEVICE_ATTR_RO(interface_type);
-
-static struct attribute *interface_unipro_attrs[] = {
- &dev_attr_ddbl1_manufacturer_id.attr,
- &dev_attr_ddbl1_product_id.attr,
- NULL
-};
-
-static struct attribute *interface_greybus_attrs[] = {
- &dev_attr_vendor_id.attr,
- &dev_attr_product_id.attr,
- &dev_attr_serial_number.attr,
- NULL
-};
-
-static struct attribute *interface_power_attrs[] = {
- &dev_attr_voltage_now.attr,
- &dev_attr_current_now.attr,
- &dev_attr_power_now.attr,
- &dev_attr_power_state.attr,
- NULL
-};
-
-static struct attribute *interface_common_attrs[] = {
- &dev_attr_interface_id.attr,
- &dev_attr_interface_type.attr,
- NULL
-};
-
-static umode_t interface_unipro_is_visible(struct kobject *kobj,
- struct attribute *attr, int n)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct gb_interface *intf = to_gb_interface(dev);
-
- switch (intf->type) {
- case GB_INTERFACE_TYPE_UNIPRO:
- case GB_INTERFACE_TYPE_GREYBUS:
- return attr->mode;
- default:
- return 0;
- }
-}
-
-static umode_t interface_greybus_is_visible(struct kobject *kobj,
- struct attribute *attr, int n)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct gb_interface *intf = to_gb_interface(dev);
-
- switch (intf->type) {
- case GB_INTERFACE_TYPE_GREYBUS:
- return attr->mode;
- default:
- return 0;
- }
-}
-
-static umode_t interface_power_is_visible(struct kobject *kobj,
- struct attribute *attr, int n)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct gb_interface *intf = to_gb_interface(dev);
-
- switch (intf->type) {
- case GB_INTERFACE_TYPE_UNIPRO:
- case GB_INTERFACE_TYPE_GREYBUS:
- return attr->mode;
- default:
- return 0;
- }
-}
-
-static const struct attribute_group interface_unipro_group = {
- .is_visible = interface_unipro_is_visible,
- .attrs = interface_unipro_attrs,
-};
-
-static const struct attribute_group interface_greybus_group = {
- .is_visible = interface_greybus_is_visible,
- .attrs = interface_greybus_attrs,
-};
-
-static const struct attribute_group interface_power_group = {
- .is_visible = interface_power_is_visible,
- .attrs = interface_power_attrs,
-};
-
-static const struct attribute_group interface_common_group = {
- .attrs = interface_common_attrs,
-};
-
-static const struct attribute_group *interface_groups[] = {
- &interface_unipro_group,
- &interface_greybus_group,
- &interface_power_group,
- &interface_common_group,
- NULL
-};
-
-static void gb_interface_release(struct device *dev)
-{
- struct gb_interface *intf = to_gb_interface(dev);
-
- trace_gb_interface_release(intf);
-
- kfree(intf);
-}
-
-#ifdef CONFIG_PM
-static int gb_interface_suspend(struct device *dev)
-{
- struct gb_interface *intf = to_gb_interface(dev);
- int ret;
-
- ret = gb_control_interface_suspend_prepare(intf->control);
- if (ret)
- return ret;
-
- ret = gb_control_suspend(intf->control);
- if (ret)
- goto err_hibernate_abort;
-
- ret = gb_interface_hibernate_link(intf);
- if (ret)
- return ret;
-
- /* Delay to allow interface to enter standby before disabling refclk */
- msleep(GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS);
-
- ret = gb_interface_refclk_set(intf, false);
- if (ret)
- return ret;
-
- return 0;
-
-err_hibernate_abort:
- gb_control_interface_hibernate_abort(intf->control);
-
- return ret;
-}
-
-static int gb_interface_resume(struct device *dev)
-{
- struct gb_interface *intf = to_gb_interface(dev);
- struct gb_svc *svc = intf->hd->svc;
- int ret;
-
- ret = gb_interface_refclk_set(intf, true);
- if (ret)
- return ret;
-
- ret = gb_svc_intf_resume(svc, intf->interface_id);
- if (ret)
- return ret;
-
- ret = gb_control_resume(intf->control);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int gb_interface_runtime_idle(struct device *dev)
-{
- pm_runtime_mark_last_busy(dev);
- pm_request_autosuspend(dev);
-
- return 0;
-}
-#endif
-
-static const struct dev_pm_ops gb_interface_pm_ops = {
- SET_RUNTIME_PM_OPS(gb_interface_suspend, gb_interface_resume,
- gb_interface_runtime_idle)
-};
-
-struct device_type greybus_interface_type = {
- .name = "greybus_interface",
- .release = gb_interface_release,
- .pm = &gb_interface_pm_ops,
-};
-
-/*
- * A Greybus module represents a user-replaceable component on a GMP
- * phone. An interface is the physical connection on that module. A
- * module may have more than one interface.
- *
- * Create a gb_interface structure to represent a discovered interface.
- * The position of interface within the Endo is encoded in "interface_id"
- * argument.
- *
- * Returns a pointer to the new interfce or a null pointer if a
- * failure occurs due to memory exhaustion.
- */
-struct gb_interface *gb_interface_create(struct gb_module *module,
- u8 interface_id)
-{
- struct gb_host_device *hd = module->hd;
- struct gb_interface *intf;
-
- intf = kzalloc(sizeof(*intf), GFP_KERNEL);
- if (!intf)
- return NULL;
-
- intf->hd = hd; /* XXX refcount? */
- intf->module = module;
- intf->interface_id = interface_id;
- INIT_LIST_HEAD(&intf->bundles);
- INIT_LIST_HEAD(&intf->manifest_descs);
- mutex_init(&intf->mutex);
- INIT_WORK(&intf->mode_switch_work, gb_interface_mode_switch_work);
- init_completion(&intf->mode_switch_completion);
-
- /* Invalid device id to start with */
- intf->device_id = GB_INTERFACE_DEVICE_ID_BAD;
-
- intf->dev.parent = &module->dev;
- intf->dev.bus = &greybus_bus_type;
- intf->dev.type = &greybus_interface_type;
- intf->dev.groups = interface_groups;
- intf->dev.dma_mask = module->dev.dma_mask;
- device_initialize(&intf->dev);
- dev_set_name(&intf->dev, "%s.%u", dev_name(&module->dev),
- interface_id);
-
- pm_runtime_set_autosuspend_delay(&intf->dev,
- GB_INTERFACE_AUTOSUSPEND_MS);
-
- trace_gb_interface_create(intf);
-
- return intf;
-}
-
-static int gb_interface_vsys_set(struct gb_interface *intf, bool enable)
-{
- struct gb_svc *svc = intf->hd->svc;
- int ret;
-
- dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
-
- ret = gb_svc_intf_vsys_set(svc, intf->interface_id, enable);
- if (ret) {
- dev_err(&intf->dev, "failed to set v_sys: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static int gb_interface_refclk_set(struct gb_interface *intf, bool enable)
-{
- struct gb_svc *svc = intf->hd->svc;
- int ret;
-
- dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
-
- ret = gb_svc_intf_refclk_set(svc, intf->interface_id, enable);
- if (ret) {
- dev_err(&intf->dev, "failed to set refclk: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static int gb_interface_unipro_set(struct gb_interface *intf, bool enable)
-{
- struct gb_svc *svc = intf->hd->svc;
- int ret;
-
- dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
-
- ret = gb_svc_intf_unipro_set(svc, intf->interface_id, enable);
- if (ret) {
- dev_err(&intf->dev, "failed to set UniPro: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static int gb_interface_activate_operation(struct gb_interface *intf,
- enum gb_interface_type *intf_type)
-{
- struct gb_svc *svc = intf->hd->svc;
- u8 type;
- int ret;
-
- dev_dbg(&intf->dev, "%s\n", __func__);
-
- ret = gb_svc_intf_activate(svc, intf->interface_id, &type);
- if (ret) {
- dev_err(&intf->dev, "failed to activate: %d\n", ret);
- return ret;
- }
-
- switch (type) {
- case GB_SVC_INTF_TYPE_DUMMY:
- *intf_type = GB_INTERFACE_TYPE_DUMMY;
- /* FIXME: handle as an error for now */
- return -ENODEV;
- case GB_SVC_INTF_TYPE_UNIPRO:
- *intf_type = GB_INTERFACE_TYPE_UNIPRO;
- dev_err(&intf->dev, "interface type UniPro not supported\n");
- /* FIXME: handle as an error for now */
- return -ENODEV;
- case GB_SVC_INTF_TYPE_GREYBUS:
- *intf_type = GB_INTERFACE_TYPE_GREYBUS;
- break;
- default:
- dev_err(&intf->dev, "unknown interface type: %u\n", type);
- *intf_type = GB_INTERFACE_TYPE_UNKNOWN;
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int gb_interface_hibernate_link(struct gb_interface *intf)
-{
- struct gb_svc *svc = intf->hd->svc;
-
- return gb_svc_intf_set_power_mode_hibernate(svc, intf->interface_id);
-}
-
-static int _gb_interface_activate(struct gb_interface *intf,
- enum gb_interface_type *type)
-{
- int ret;
-
- *type = GB_INTERFACE_TYPE_UNKNOWN;
-
- if (intf->ejected || intf->removed)
- return -ENODEV;
-
- ret = gb_interface_vsys_set(intf, true);
- if (ret)
- return ret;
-
- ret = gb_interface_refclk_set(intf, true);
- if (ret)
- goto err_vsys_disable;
-
- ret = gb_interface_unipro_set(intf, true);
- if (ret)
- goto err_refclk_disable;
-
- ret = gb_interface_activate_operation(intf, type);
- if (ret) {
- switch (*type) {
- case GB_INTERFACE_TYPE_UNIPRO:
- case GB_INTERFACE_TYPE_GREYBUS:
- goto err_hibernate_link;
- default:
- goto err_unipro_disable;
- }
- }
-
- ret = gb_interface_read_dme(intf);
- if (ret)
- goto err_hibernate_link;
-
- ret = gb_interface_route_create(intf);
- if (ret)
- goto err_hibernate_link;
-
- intf->active = true;
-
- trace_gb_interface_activate(intf);
-
- return 0;
-
-err_hibernate_link:
- gb_interface_hibernate_link(intf);
-err_unipro_disable:
- gb_interface_unipro_set(intf, false);
-err_refclk_disable:
- gb_interface_refclk_set(intf, false);
-err_vsys_disable:
- gb_interface_vsys_set(intf, false);
-
- return ret;
-}
-
-/*
- * At present, we assume a UniPro-only module to be a Greybus module that
- * failed to send its mailbox poke. There is some reason to believe that this
- * is because of a bug in the ES3 bootrom.
- *
- * FIXME: Check if this is a Toshiba bridge before retrying?
- */
-static int _gb_interface_activate_es3_hack(struct gb_interface *intf,
- enum gb_interface_type *type)
-{
- int retries = 3;
- int ret;
-
- while (retries--) {
- ret = _gb_interface_activate(intf, type);
- if (ret == -ENODEV && *type == GB_INTERFACE_TYPE_UNIPRO)
- continue;
-
- break;
- }
-
- return ret;
-}
-
-/*
- * Activate an interface.
- *
- * Locking: Caller holds the interface mutex.
- */
-int gb_interface_activate(struct gb_interface *intf)
-{
- enum gb_interface_type type;
- int ret;
-
- switch (intf->type) {
- case GB_INTERFACE_TYPE_INVALID:
- case GB_INTERFACE_TYPE_GREYBUS:
- ret = _gb_interface_activate_es3_hack(intf, &type);
- break;
- default:
- ret = _gb_interface_activate(intf, &type);
- }
-
- /* Make sure type is detected correctly during reactivation. */
- if (intf->type != GB_INTERFACE_TYPE_INVALID) {
- if (type != intf->type) {
- dev_err(&intf->dev, "failed to detect interface type\n");
-
- if (!ret)
- gb_interface_deactivate(intf);
-
- return -EIO;
- }
- } else {
- intf->type = type;
- }
-
- return ret;
-}
-
-/*
- * Deactivate an interface.
- *
- * Locking: Caller holds the interface mutex.
- */
-void gb_interface_deactivate(struct gb_interface *intf)
-{
- if (!intf->active)
- return;
-
- trace_gb_interface_deactivate(intf);
-
- /* Abort any ongoing mode switch. */
- if (intf->mode_switch)
- complete(&intf->mode_switch_completion);
-
- gb_interface_route_destroy(intf);
- gb_interface_hibernate_link(intf);
- gb_interface_unipro_set(intf, false);
- gb_interface_refclk_set(intf, false);
- gb_interface_vsys_set(intf, false);
-
- intf->active = false;
-}
-
-/*
- * Enable an interface by enabling its control connection, fetching the
- * manifest and other information over it, and finally registering its child
- * devices.
- *
- * Locking: Caller holds the interface mutex.
- */
-int gb_interface_enable(struct gb_interface *intf)
-{
- struct gb_control *control;
- struct gb_bundle *bundle, *tmp;
- int ret, size;
- void *manifest;
-
- ret = gb_interface_read_and_clear_init_status(intf);
- if (ret) {
- dev_err(&intf->dev, "failed to clear init status: %d\n", ret);
- return ret;
- }
-
- /* Establish control connection */
- control = gb_control_create(intf);
- if (IS_ERR(control)) {
- dev_err(&intf->dev, "failed to create control device: %ld\n",
- PTR_ERR(control));
- return PTR_ERR(control);
- }
- intf->control = control;
-
- ret = gb_control_enable(intf->control);
- if (ret)
- goto err_put_control;
-
- /* Get manifest size using control protocol on CPort */
- size = gb_control_get_manifest_size_operation(intf);
- if (size <= 0) {
- dev_err(&intf->dev, "failed to get manifest size: %d\n", size);
-
- if (size)
- ret = size;
- else
- ret = -EINVAL;
-
- goto err_disable_control;
- }
-
- manifest = kmalloc(size, GFP_KERNEL);
- if (!manifest) {
- ret = -ENOMEM;
- goto err_disable_control;
- }
-
- /* Get manifest using control protocol on CPort */
- ret = gb_control_get_manifest_operation(intf, manifest, size);
- if (ret) {
- dev_err(&intf->dev, "failed to get manifest: %d\n", ret);
- goto err_free_manifest;
- }
-
- /*
- * Parse the manifest and build up our data structures representing
- * what's in it.
- */
- if (!gb_manifest_parse(intf, manifest, size)) {
- dev_err(&intf->dev, "failed to parse manifest\n");
- ret = -EINVAL;
- goto err_destroy_bundles;
- }
-
- ret = gb_control_get_bundle_versions(intf->control);
- if (ret)
- goto err_destroy_bundles;
-
- /* Register the control device and any bundles */
- ret = gb_control_add(intf->control);
- if (ret)
- goto err_destroy_bundles;
-
- pm_runtime_use_autosuspend(&intf->dev);
- pm_runtime_get_noresume(&intf->dev);
- pm_runtime_set_active(&intf->dev);
- pm_runtime_enable(&intf->dev);
-
- list_for_each_entry_safe_reverse(bundle, tmp, &intf->bundles, links) {
- ret = gb_bundle_add(bundle);
- if (ret) {
- gb_bundle_destroy(bundle);
- continue;
- }
- }
-
- kfree(manifest);
-
- intf->enabled = true;
-
- pm_runtime_put(&intf->dev);
-
- trace_gb_interface_enable(intf);
-
- return 0;
-
-err_destroy_bundles:
- list_for_each_entry_safe(bundle, tmp, &intf->bundles, links)
- gb_bundle_destroy(bundle);
-err_free_manifest:
- kfree(manifest);
-err_disable_control:
- gb_control_disable(intf->control);
-err_put_control:
- gb_control_put(intf->control);
- intf->control = NULL;
-
- return ret;
-}
-
-/*
- * Disable an interface and destroy its bundles.
- *
- * Locking: Caller holds the interface mutex.
- */
-void gb_interface_disable(struct gb_interface *intf)
-{
- struct gb_bundle *bundle;
- struct gb_bundle *next;
-
- if (!intf->enabled)
- return;
-
- trace_gb_interface_disable(intf);
-
- pm_runtime_get_sync(&intf->dev);
-
- /* Set disconnected flag to avoid I/O during connection tear down. */
- if (intf->quirks & GB_INTERFACE_QUIRK_FORCED_DISABLE)
- intf->disconnected = true;
-
- list_for_each_entry_safe(bundle, next, &intf->bundles, links)
- gb_bundle_destroy(bundle);
-
- if (!intf->mode_switch && !intf->disconnected)
- gb_control_interface_deactivate_prepare(intf->control);
-
- gb_control_del(intf->control);
- gb_control_disable(intf->control);
- gb_control_put(intf->control);
- intf->control = NULL;
-
- intf->enabled = false;
-
- pm_runtime_disable(&intf->dev);
- pm_runtime_set_suspended(&intf->dev);
- pm_runtime_dont_use_autosuspend(&intf->dev);
- pm_runtime_put_noidle(&intf->dev);
-}
-
-/* Register an interface. */
-int gb_interface_add(struct gb_interface *intf)
-{
- int ret;
-
- ret = device_add(&intf->dev);
- if (ret) {
- dev_err(&intf->dev, "failed to register interface: %d\n", ret);
- return ret;
- }
-
- trace_gb_interface_add(intf);
-
- dev_info(&intf->dev, "Interface added (%s)\n",
- gb_interface_type_string(intf));
-
- switch (intf->type) {
- case GB_INTERFACE_TYPE_GREYBUS:
- dev_info(&intf->dev, "GMP VID=0x%08x, PID=0x%08x\n",
- intf->vendor_id, intf->product_id);
- /* fall-through */
- case GB_INTERFACE_TYPE_UNIPRO:
- dev_info(&intf->dev, "DDBL1 Manufacturer=0x%08x, Product=0x%08x\n",
- intf->ddbl1_manufacturer_id,
- intf->ddbl1_product_id);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-/* Deregister an interface. */
-void gb_interface_del(struct gb_interface *intf)
-{
- if (device_is_registered(&intf->dev)) {
- trace_gb_interface_del(intf);
-
- device_del(&intf->dev);
- dev_info(&intf->dev, "Interface removed\n");
- }
-}
-
-void gb_interface_put(struct gb_interface *intf)
-{
- put_device(&intf->dev);
-}
diff --git a/drivers/staging/greybus/interface.h b/drivers/staging/greybus/interface.h
deleted file mode 100644
index 1c00c5bb3ec9..000000000000
--- a/drivers/staging/greybus/interface.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus Interface Block code
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- */
-
-#ifndef __INTERFACE_H
-#define __INTERFACE_H
-
-enum gb_interface_type {
- GB_INTERFACE_TYPE_INVALID = 0,
- GB_INTERFACE_TYPE_UNKNOWN,
- GB_INTERFACE_TYPE_DUMMY,
- GB_INTERFACE_TYPE_UNIPRO,
- GB_INTERFACE_TYPE_GREYBUS,
-};
-
-#define GB_INTERFACE_QUIRK_NO_CPORT_FEATURES BIT(0)
-#define GB_INTERFACE_QUIRK_NO_INIT_STATUS BIT(1)
-#define GB_INTERFACE_QUIRK_NO_GMP_IDS BIT(2)
-#define GB_INTERFACE_QUIRK_FORCED_DISABLE BIT(3)
-#define GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH BIT(4)
-#define GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE BIT(5)
-#define GB_INTERFACE_QUIRK_NO_PM BIT(6)
-
-struct gb_interface {
- struct device dev;
- struct gb_control *control;
-
- struct list_head bundles;
- struct list_head module_node;
- struct list_head manifest_descs;
- u8 interface_id; /* Physical location within the Endo */
- u8 device_id;
- u8 features; /* Feature flags set in the manifest */
-
- enum gb_interface_type type;
-
- u32 ddbl1_manufacturer_id;
- u32 ddbl1_product_id;
- u32 vendor_id;
- u32 product_id;
- u64 serial_number;
-
- struct gb_host_device *hd;
- struct gb_module *module;
-
- unsigned long quirks;
-
- struct mutex mutex;
-
- bool disconnected;
-
- bool ejected;
- bool removed;
- bool active;
- bool enabled;
- bool mode_switch;
- bool dme_read;
-
- struct work_struct mode_switch_work;
- struct completion mode_switch_completion;
-};
-#define to_gb_interface(d) container_of(d, struct gb_interface, dev)
-
-struct gb_interface *gb_interface_create(struct gb_module *module,
- u8 interface_id);
-int gb_interface_activate(struct gb_interface *intf);
-void gb_interface_deactivate(struct gb_interface *intf);
-int gb_interface_enable(struct gb_interface *intf);
-void gb_interface_disable(struct gb_interface *intf);
-int gb_interface_add(struct gb_interface *intf);
-void gb_interface_del(struct gb_interface *intf);
-void gb_interface_put(struct gb_interface *intf);
-void gb_interface_mailbox_event(struct gb_interface *intf, u16 result,
- u32 mailbox);
-
-int gb_interface_request_mode_switch(struct gb_interface *intf);
-
-#endif /* __INTERFACE_H */
diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c
index 010ae1e9c7fb..d6ba25f21d80 100644
--- a/drivers/staging/greybus/light.c
+++ b/drivers/staging/greybus/light.c
@@ -11,11 +11,9 @@
#include <linux/led-class-flash.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/greybus.h>
#include <media/v4l2-flash-led-class.h>
-#include "greybus.h"
-#include "greybus_protocols.h"
-
#define NAMES_MAX 32
struct gb_channel {
@@ -1098,21 +1096,21 @@ static void gb_lights_channel_release(struct gb_channel *channel)
static void gb_lights_light_release(struct gb_light *light)
{
int i;
- int count;
light->ready = false;
- count = light->channels_count;
-
if (light->has_flash)
gb_lights_light_v4l2_unregister(light);
+ light->has_flash = false;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < light->channels_count; i++)
gb_lights_channel_release(&light->channels[i]);
- light->channels_count--;
- }
+ light->channels_count = 0;
+
kfree(light->channels);
+ light->channels = NULL;
kfree(light->name);
+ light->name = NULL;
}
static void gb_lights_release(struct gb_lights *glights)
diff --git a/drivers/staging/greybus/log.c b/drivers/staging/greybus/log.c
index 15a88574dbb0..971f36dccac6 100644
--- a/drivers/staging/greybus/log.c
+++ b/drivers/staging/greybus/log.c
@@ -9,8 +9,7 @@
#include <linux/slab.h>
#include <linux/sizes.h>
#include <linux/uaccess.h>
-
-#include "greybus.h"
+#include <linux/greybus.h>
struct gb_log {
struct gb_connection *connection;
@@ -31,14 +30,14 @@ static int gb_log_request_handler(struct gb_operation *op)
/* Verify size of payload */
if (op->request->payload_size < sizeof(*receive)) {
dev_err(dev, "log request too small (%zu < %zu)\n",
- op->request->payload_size, sizeof(*receive));
+ op->request->payload_size, sizeof(*receive));
return -EINVAL;
}
receive = op->request->payload;
len = le16_to_cpu(receive->len);
if (len != (op->request->payload_size - sizeof(*receive))) {
dev_err(dev, "log request wrong size %d vs %zu\n", len,
- (op->request->payload_size - sizeof(*receive)));
+ (op->request->payload_size - sizeof(*receive)));
return -EINVAL;
}
if (len == 0) {
@@ -83,7 +82,7 @@ static int gb_log_probe(struct gb_bundle *bundle,
return -ENOMEM;
connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
- gb_log_request_handler);
+ gb_log_request_handler);
if (IS_ERR(connection)) {
retval = PTR_ERR(connection);
goto error_free;
diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c
index 48d85ebe404a..583d9708a191 100644
--- a/drivers/staging/greybus/loopback.c
+++ b/drivers/staging/greybus/loopback.c
@@ -25,12 +25,9 @@
#include <linux/workqueue.h>
#include <linux/atomic.h>
#include <linux/pm_runtime.h>
-
+#include <linux/greybus.h>
#include <asm/div64.h>
-#include "greybus.h"
-#include "connection.h"
-
#define NSEC_PER_DAY 86400000000000ULL
struct gb_loopback_stats {
@@ -882,7 +879,7 @@ static int gb_loopback_fn(void *data)
gb->type = 0;
gb->send_count = 0;
sysfs_notify(&gb->dev->kobj, NULL,
- "iteration_count");
+ "iteration_count");
dev_dbg(&bundle->dev, "load test complete\n");
} else {
dev_dbg(&bundle->dev,
@@ -1054,7 +1051,7 @@ static int gb_loopback_probe(struct gb_bundle *bundle,
/* Allocate kfifo */
if (kfifo_alloc(&gb->kfifo_lat, kfifo_depth * sizeof(u32),
- GFP_KERNEL)) {
+ GFP_KERNEL)) {
retval = -ENOMEM;
goto out_conn;
}
diff --git a/drivers/staging/greybus/manifest.c b/drivers/staging/greybus/manifest.c
deleted file mode 100644
index 08db49264f2b..000000000000
--- a/drivers/staging/greybus/manifest.c
+++ /dev/null
@@ -1,534 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus manifest parsing
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- */
-
-#include "greybus.h"
-
-static const char *get_descriptor_type_string(u8 type)
-{
- switch (type) {
- case GREYBUS_TYPE_INVALID:
- return "invalid";
- case GREYBUS_TYPE_STRING:
- return "string";
- case GREYBUS_TYPE_INTERFACE:
- return "interface";
- case GREYBUS_TYPE_CPORT:
- return "cport";
- case GREYBUS_TYPE_BUNDLE:
- return "bundle";
- default:
- WARN_ON(1);
- return "unknown";
- }
-}
-
-/*
- * We scan the manifest once to identify where all the descriptors
- * are. The result is a list of these manifest_desc structures. We
- * then pick through them for what we're looking for (starting with
- * the interface descriptor). As each is processed we remove it from
- * the list. When we're done the list should (probably) be empty.
- */
-struct manifest_desc {
- struct list_head links;
-
- size_t size;
- void *data;
- enum greybus_descriptor_type type;
-};
-
-static void release_manifest_descriptor(struct manifest_desc *descriptor)
-{
- list_del(&descriptor->links);
- kfree(descriptor);
-}
-
-static void release_manifest_descriptors(struct gb_interface *intf)
-{
- struct manifest_desc *descriptor;
- struct manifest_desc *next;
-
- list_for_each_entry_safe(descriptor, next, &intf->manifest_descs, links)
- release_manifest_descriptor(descriptor);
-}
-
-static void release_cport_descriptors(struct list_head *head, u8 bundle_id)
-{
- struct manifest_desc *desc, *tmp;
- struct greybus_descriptor_cport *desc_cport;
-
- list_for_each_entry_safe(desc, tmp, head, links) {
- desc_cport = desc->data;
-
- if (desc->type != GREYBUS_TYPE_CPORT)
- continue;
-
- if (desc_cport->bundle == bundle_id)
- release_manifest_descriptor(desc);
- }
-}
-
-static struct manifest_desc *get_next_bundle_desc(struct gb_interface *intf)
-{
- struct manifest_desc *descriptor;
- struct manifest_desc *next;
-
- list_for_each_entry_safe(descriptor, next, &intf->manifest_descs, links)
- if (descriptor->type == GREYBUS_TYPE_BUNDLE)
- return descriptor;
-
- return NULL;
-}
-
-/*
- * Validate the given descriptor. Its reported size must fit within
- * the number of bytes remaining, and it must have a recognized
- * type. Check that the reported size is at least as big as what
- * we expect to see. (It could be bigger, perhaps for a new version
- * of the format.)
- *
- * Returns the (non-zero) number of bytes consumed by the descriptor,
- * or a negative errno.
- */
-static int identify_descriptor(struct gb_interface *intf,
- struct greybus_descriptor *desc, size_t size)
-{
- struct greybus_descriptor_header *desc_header = &desc->header;
- struct manifest_desc *descriptor;
- size_t desc_size;
- size_t expected_size;
-
- if (size < sizeof(*desc_header)) {
- dev_err(&intf->dev, "manifest too small (%zu < %zu)\n",
- size, sizeof(*desc_header));
- return -EINVAL; /* Must at least have header */
- }
-
- desc_size = le16_to_cpu(desc_header->size);
- if (desc_size > size) {
- dev_err(&intf->dev, "descriptor too big (%zu > %zu)\n",
- desc_size, size);
- return -EINVAL;
- }
-
- /* Descriptor needs to at least have a header */
- expected_size = sizeof(*desc_header);
-
- switch (desc_header->type) {
- case GREYBUS_TYPE_STRING:
- expected_size += sizeof(struct greybus_descriptor_string);
- expected_size += desc->string.length;
-
- /* String descriptors are padded to 4 byte boundaries */
- expected_size = ALIGN(expected_size, 4);
- break;
- case GREYBUS_TYPE_INTERFACE:
- expected_size += sizeof(struct greybus_descriptor_interface);
- break;
- case GREYBUS_TYPE_BUNDLE:
- expected_size += sizeof(struct greybus_descriptor_bundle);
- break;
- case GREYBUS_TYPE_CPORT:
- expected_size += sizeof(struct greybus_descriptor_cport);
- break;
- case GREYBUS_TYPE_INVALID:
- default:
- dev_err(&intf->dev, "invalid descriptor type (%u)\n",
- desc_header->type);
- return -EINVAL;
- }
-
- if (desc_size < expected_size) {
- dev_err(&intf->dev, "%s descriptor too small (%zu < %zu)\n",
- get_descriptor_type_string(desc_header->type),
- desc_size, expected_size);
- return -EINVAL;
- }
-
- /* Descriptor bigger than what we expect */
- if (desc_size > expected_size) {
- dev_warn(&intf->dev, "%s descriptor size mismatch (want %zu got %zu)\n",
- get_descriptor_type_string(desc_header->type),
- expected_size, desc_size);
- }
-
- descriptor = kzalloc(sizeof(*descriptor), GFP_KERNEL);
- if (!descriptor)
- return -ENOMEM;
-
- descriptor->size = desc_size;
- descriptor->data = (char *)desc + sizeof(*desc_header);
- descriptor->type = desc_header->type;
- list_add_tail(&descriptor->links, &intf->manifest_descs);
-
- /* desc_size is positive and is known to fit in a signed int */
-
- return desc_size;
-}
-
-/*
- * Find the string descriptor having the given id, validate it, and
- * allocate a duplicate copy of it. The duplicate has an extra byte
- * which guarantees the returned string is NUL-terminated.
- *
- * String index 0 is valid (it represents "no string"), and for
- * that a null pointer is returned.
- *
- * Otherwise returns a pointer to a newly-allocated copy of the
- * descriptor string, or an error-coded pointer on failure.
- */
-static char *gb_string_get(struct gb_interface *intf, u8 string_id)
-{
- struct greybus_descriptor_string *desc_string;
- struct manifest_desc *descriptor;
- bool found = false;
- char *string;
-
- /* A zero string id means no string (but no error) */
- if (!string_id)
- return NULL;
-
- list_for_each_entry(descriptor, &intf->manifest_descs, links) {
- if (descriptor->type != GREYBUS_TYPE_STRING)
- continue;
-
- desc_string = descriptor->data;
- if (desc_string->id == string_id) {
- found = true;
- break;
- }
- }
- if (!found)
- return ERR_PTR(-ENOENT);
-
- /* Allocate an extra byte so we can guarantee it's NUL-terminated */
- string = kmemdup(&desc_string->string, desc_string->length + 1,
- GFP_KERNEL);
- if (!string)
- return ERR_PTR(-ENOMEM);
- string[desc_string->length] = '\0';
-
- /* Ok we've used this string, so we're done with it */
- release_manifest_descriptor(descriptor);
-
- return string;
-}
-
-/*
- * Find cport descriptors in the manifest associated with the given
- * bundle, and set up data structures for the functions that use
- * them. Returns the number of cports set up for the bundle, or 0
- * if there is an error.
- */
-static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
-{
- struct gb_interface *intf = bundle->intf;
- struct greybus_descriptor_cport *desc_cport;
- struct manifest_desc *desc, *next, *tmp;
- LIST_HEAD(list);
- u8 bundle_id = bundle->id;
- u16 cport_id;
- u32 count = 0;
- int i;
-
- /* Set up all cport descriptors associated with this bundle */
- list_for_each_entry_safe(desc, next, &intf->manifest_descs, links) {
- if (desc->type != GREYBUS_TYPE_CPORT)
- continue;
-
- desc_cport = desc->data;
- if (desc_cport->bundle != bundle_id)
- continue;
-
- cport_id = le16_to_cpu(desc_cport->id);
- if (cport_id > CPORT_ID_MAX)
- goto exit;
-
- /* Nothing else should have its cport_id as control cport id */
- if (cport_id == GB_CONTROL_CPORT_ID) {
- dev_err(&bundle->dev, "invalid cport id found (%02u)\n",
- cport_id);
- goto exit;
- }
-
- /*
- * Found one, move it to our temporary list after checking for
- * duplicates.
- */
- list_for_each_entry(tmp, &list, links) {
- desc_cport = tmp->data;
- if (cport_id == le16_to_cpu(desc_cport->id)) {
- dev_err(&bundle->dev,
- "duplicate CPort %u found\n",
- cport_id);
- goto exit;
- }
- }
- list_move_tail(&desc->links, &list);
- count++;
- }
-
- if (!count)
- return 0;
-
- bundle->cport_desc = kcalloc(count, sizeof(*bundle->cport_desc),
- GFP_KERNEL);
- if (!bundle->cport_desc)
- goto exit;
-
- bundle->num_cports = count;
-
- i = 0;
- list_for_each_entry_safe(desc, next, &list, links) {
- desc_cport = desc->data;
- memcpy(&bundle->cport_desc[i++], desc_cport,
- sizeof(*desc_cport));
-
- /* Release the cport descriptor */
- release_manifest_descriptor(desc);
- }
-
- return count;
-exit:
- release_cport_descriptors(&list, bundle_id);
- /*
- * Free all cports for this bundle to avoid 'excess descriptors'
- * warnings.
- */
- release_cport_descriptors(&intf->manifest_descs, bundle_id);
-
- return 0; /* Error; count should also be 0 */
-}
-
-/*
- * Find bundle descriptors in the manifest and set up their data
- * structures. Returns the number of bundles set up for the
- * given interface.
- */
-static u32 gb_manifest_parse_bundles(struct gb_interface *intf)
-{
- struct manifest_desc *desc;
- struct gb_bundle *bundle;
- struct gb_bundle *bundle_next;
- u32 count = 0;
- u8 bundle_id;
- u8 class;
-
- while ((desc = get_next_bundle_desc(intf))) {
- struct greybus_descriptor_bundle *desc_bundle;
-
- /* Found one. Set up its bundle structure*/
- desc_bundle = desc->data;
- bundle_id = desc_bundle->id;
- class = desc_bundle->class;
-
- /* Done with this bundle descriptor */
- release_manifest_descriptor(desc);
-
- /* Ignore any legacy control bundles */
- if (bundle_id == GB_CONTROL_BUNDLE_ID) {
- dev_dbg(&intf->dev, "%s - ignoring control bundle\n",
- __func__);
- release_cport_descriptors(&intf->manifest_descs,
- bundle_id);
- continue;
- }
-
- /* Nothing else should have its class set to control class */
- if (class == GREYBUS_CLASS_CONTROL) {
- dev_err(&intf->dev,
- "bundle %u cannot use control class\n",
- bundle_id);
- goto cleanup;
- }
-
- bundle = gb_bundle_create(intf, bundle_id, class);
- if (!bundle)
- goto cleanup;
-
- /*
- * Now go set up this bundle's functions and cports.
- *
- * A 'bundle' represents a device in greybus. It may require
- * multiple cports for its functioning. If we fail to setup any
- * cport of a bundle, we better reject the complete bundle as
- * the device may not be able to function properly then.
- *
- * But, failing to setup a cport of bundle X doesn't mean that
- * the device corresponding to bundle Y will not work properly.
- * Bundles should be treated as separate independent devices.
- *
- * While parsing manifest for an interface, treat bundles as
- * separate entities and don't reject entire interface and its
- * bundles on failing to initialize a cport. But make sure the
- * bundle which needs the cport, gets destroyed properly.
- */
- if (!gb_manifest_parse_cports(bundle)) {
- gb_bundle_destroy(bundle);
- continue;
- }
-
- count++;
- }
-
- return count;
-cleanup:
- /* An error occurred; undo any changes we've made */
- list_for_each_entry_safe(bundle, bundle_next, &intf->bundles, links) {
- gb_bundle_destroy(bundle);
- count--;
- }
- return 0; /* Error; count should also be 0 */
-}
-
-static bool gb_manifest_parse_interface(struct gb_interface *intf,
- struct manifest_desc *interface_desc)
-{
- struct greybus_descriptor_interface *desc_intf = interface_desc->data;
- struct gb_control *control = intf->control;
- char *str;
-
- /* Handle the strings first--they can fail */
- str = gb_string_get(intf, desc_intf->vendor_stringid);
- if (IS_ERR(str))
- return false;
- control->vendor_string = str;
-
- str = gb_string_get(intf, desc_intf->product_stringid);
- if (IS_ERR(str))
- goto out_free_vendor_string;
- control->product_string = str;
-
- /* Assign feature flags communicated via manifest */
- intf->features = desc_intf->features;
-
- /* Release the interface descriptor, now that we're done with it */
- release_manifest_descriptor(interface_desc);
-
- /* An interface must have at least one bundle descriptor */
- if (!gb_manifest_parse_bundles(intf)) {
- dev_err(&intf->dev, "manifest bundle descriptors not valid\n");
- goto out_err;
- }
-
- return true;
-out_err:
- kfree(control->product_string);
- control->product_string = NULL;
-out_free_vendor_string:
- kfree(control->vendor_string);
- control->vendor_string = NULL;
-
- return false;
-}
-
-/*
- * Parse a buffer containing an interface manifest.
- *
- * If we find anything wrong with the content/format of the buffer
- * we reject it.
- *
- * The first requirement is that the manifest's version is
- * one we can parse.
- *
- * We make an initial pass through the buffer and identify all of
- * the descriptors it contains, keeping track for each its type
- * and the location size of its data in the buffer.
- *
- * Next we scan the descriptors, looking for an interface descriptor;
- * there must be exactly one of those. When found, we record the
- * information it contains, and then remove that descriptor (and any
- * string descriptors it refers to) from further consideration.
- *
- * After that we look for the interface's bundles--there must be at
- * least one of those.
- *
- * Returns true if parsing was successful, false otherwise.
- */
-bool gb_manifest_parse(struct gb_interface *intf, void *data, size_t size)
-{
- struct greybus_manifest *manifest;
- struct greybus_manifest_header *header;
- struct greybus_descriptor *desc;
- struct manifest_desc *descriptor;
- struct manifest_desc *interface_desc = NULL;
- u16 manifest_size;
- u32 found = 0;
- bool result;
-
- /* Manifest descriptor list should be empty here */
- if (WARN_ON(!list_empty(&intf->manifest_descs)))
- return false;
-
- /* we have to have at _least_ the manifest header */
- if (size < sizeof(*header)) {
- dev_err(&intf->dev, "short manifest (%zu < %zu)\n",
- size, sizeof(*header));
- return false;
- }
-
- /* Make sure the size is right */
- manifest = data;
- header = &manifest->header;
- manifest_size = le16_to_cpu(header->size);
- if (manifest_size != size) {
- dev_err(&intf->dev, "manifest size mismatch (%zu != %u)\n",
- size, manifest_size);
- return false;
- }
-
- /* Validate major/minor number */
- if (header->version_major > GREYBUS_VERSION_MAJOR) {
- dev_err(&intf->dev, "manifest version too new (%u.%u > %u.%u)\n",
- header->version_major, header->version_minor,
- GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR);
- return false;
- }
-
- /* OK, find all the descriptors */
- desc = manifest->descriptors;
- size -= sizeof(*header);
- while (size) {
- int desc_size;
-
- desc_size = identify_descriptor(intf, desc, size);
- if (desc_size < 0) {
- result = false;
- goto out;
- }
- desc = (struct greybus_descriptor *)((char *)desc + desc_size);
- size -= desc_size;
- }
-
- /* There must be a single interface descriptor */
- list_for_each_entry(descriptor, &intf->manifest_descs, links) {
- if (descriptor->type == GREYBUS_TYPE_INTERFACE)
- if (!found++)
- interface_desc = descriptor;
- }
- if (found != 1) {
- dev_err(&intf->dev, "manifest must have 1 interface descriptor (%u found)\n",
- found);
- result = false;
- goto out;
- }
-
- /* Parse the manifest, starting with the interface descriptor */
- result = gb_manifest_parse_interface(intf, interface_desc);
-
- /*
- * We really should have no remaining descriptors, but we
- * don't know what newer format manifests might leave.
- */
- if (result && !list_empty(&intf->manifest_descs))
- dev_info(&intf->dev, "excess descriptors in interface manifest\n");
-out:
- release_manifest_descriptors(intf);
-
- return result;
-}
diff --git a/drivers/staging/greybus/manifest.h b/drivers/staging/greybus/manifest.h
deleted file mode 100644
index f3c95a255631..000000000000
--- a/drivers/staging/greybus/manifest.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus manifest parsing
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- */
-
-#ifndef __MANIFEST_H
-#define __MANIFEST_H
-
-struct gb_interface;
-bool gb_manifest_parse(struct gb_interface *intf, void *data, size_t size);
-
-#endif /* __MANIFEST_H */
diff --git a/drivers/staging/greybus/module.c b/drivers/staging/greybus/module.c
deleted file mode 100644
index b251a53d0e8e..000000000000
--- a/drivers/staging/greybus/module.c
+++ /dev/null
@@ -1,236 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus Module code
- *
- * Copyright 2016 Google Inc.
- * Copyright 2016 Linaro Ltd.
- */
-
-#include "greybus.h"
-#include "greybus_trace.h"
-
-static ssize_t eject_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct gb_module *module = to_gb_module(dev);
- struct gb_interface *intf;
- size_t i;
- long val;
- int ret;
-
- ret = kstrtol(buf, 0, &val);
- if (ret)
- return ret;
-
- if (!val)
- return len;
-
- for (i = 0; i < module->num_interfaces; ++i) {
- intf = module->interfaces[i];
-
- mutex_lock(&intf->mutex);
- /* Set flag to prevent concurrent activation. */
- intf->ejected = true;
- gb_interface_disable(intf);
- gb_interface_deactivate(intf);
- mutex_unlock(&intf->mutex);
- }
-
- /* Tell the SVC to eject the primary interface. */
- ret = gb_svc_intf_eject(module->hd->svc, module->module_id);
- if (ret)
- return ret;
-
- return len;
-}
-static DEVICE_ATTR_WO(eject);
-
-static ssize_t module_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_module *module = to_gb_module(dev);
-
- return sprintf(buf, "%u\n", module->module_id);
-}
-static DEVICE_ATTR_RO(module_id);
-
-static ssize_t num_interfaces_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_module *module = to_gb_module(dev);
-
- return sprintf(buf, "%zu\n", module->num_interfaces);
-}
-static DEVICE_ATTR_RO(num_interfaces);
-
-static struct attribute *module_attrs[] = {
- &dev_attr_eject.attr,
- &dev_attr_module_id.attr,
- &dev_attr_num_interfaces.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(module);
-
-static void gb_module_release(struct device *dev)
-{
- struct gb_module *module = to_gb_module(dev);
-
- trace_gb_module_release(module);
-
- kfree(module);
-}
-
-struct device_type greybus_module_type = {
- .name = "greybus_module",
- .release = gb_module_release,
-};
-
-struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id,
- size_t num_interfaces)
-{
- struct gb_interface *intf;
- struct gb_module *module;
- int i;
-
- module = kzalloc(struct_size(module, interfaces, num_interfaces),
- GFP_KERNEL);
- if (!module)
- return NULL;
-
- module->hd = hd;
- module->module_id = module_id;
- module->num_interfaces = num_interfaces;
-
- module->dev.parent = &hd->dev;
- module->dev.bus = &greybus_bus_type;
- module->dev.type = &greybus_module_type;
- module->dev.groups = module_groups;
- module->dev.dma_mask = hd->dev.dma_mask;
- device_initialize(&module->dev);
- dev_set_name(&module->dev, "%d-%u", hd->bus_id, module_id);
-
- trace_gb_module_create(module);
-
- for (i = 0; i < num_interfaces; ++i) {
- intf = gb_interface_create(module, module_id + i);
- if (!intf) {
- dev_err(&module->dev, "failed to create interface %u\n",
- module_id + i);
- goto err_put_interfaces;
- }
- module->interfaces[i] = intf;
- }
-
- return module;
-
-err_put_interfaces:
- for (--i; i >= 0; --i)
- gb_interface_put(module->interfaces[i]);
-
- put_device(&module->dev);
-
- return NULL;
-}
-
-/*
- * Register and enable an interface after first attempting to activate it.
- */
-static void gb_module_register_interface(struct gb_interface *intf)
-{
- struct gb_module *module = intf->module;
- u8 intf_id = intf->interface_id;
- int ret;
-
- mutex_lock(&intf->mutex);
-
- ret = gb_interface_activate(intf);
- if (ret) {
- if (intf->type != GB_INTERFACE_TYPE_DUMMY) {
- dev_err(&module->dev,
- "failed to activate interface %u: %d\n",
- intf_id, ret);
- }
-
- gb_interface_add(intf);
- goto err_unlock;
- }
-
- ret = gb_interface_add(intf);
- if (ret)
- goto err_interface_deactivate;
-
- ret = gb_interface_enable(intf);
- if (ret) {
- dev_err(&module->dev, "failed to enable interface %u: %d\n",
- intf_id, ret);
- goto err_interface_deactivate;
- }
-
- mutex_unlock(&intf->mutex);
-
- return;
-
-err_interface_deactivate:
- gb_interface_deactivate(intf);
-err_unlock:
- mutex_unlock(&intf->mutex);
-}
-
-static void gb_module_deregister_interface(struct gb_interface *intf)
-{
- /* Mark as disconnected to prevent I/O during disable. */
- if (intf->module->disconnected)
- intf->disconnected = true;
-
- mutex_lock(&intf->mutex);
- intf->removed = true;
- gb_interface_disable(intf);
- gb_interface_deactivate(intf);
- mutex_unlock(&intf->mutex);
-
- gb_interface_del(intf);
-}
-
-/* Register a module and its interfaces. */
-int gb_module_add(struct gb_module *module)
-{
- size_t i;
- int ret;
-
- ret = device_add(&module->dev);
- if (ret) {
- dev_err(&module->dev, "failed to register module: %d\n", ret);
- return ret;
- }
-
- trace_gb_module_add(module);
-
- for (i = 0; i < module->num_interfaces; ++i)
- gb_module_register_interface(module->interfaces[i]);
-
- return 0;
-}
-
-/* Deregister a module and its interfaces. */
-void gb_module_del(struct gb_module *module)
-{
- size_t i;
-
- for (i = 0; i < module->num_interfaces; ++i)
- gb_module_deregister_interface(module->interfaces[i]);
-
- trace_gb_module_del(module);
-
- device_del(&module->dev);
-}
-
-void gb_module_put(struct gb_module *module)
-{
- size_t i;
-
- for (i = 0; i < module->num_interfaces; ++i)
- gb_interface_put(module->interfaces[i]);
-
- put_device(&module->dev);
-}
diff --git a/drivers/staging/greybus/module.h b/drivers/staging/greybus/module.h
deleted file mode 100644
index b1ebcc6636db..000000000000
--- a/drivers/staging/greybus/module.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus Module code
- *
- * Copyright 2016 Google Inc.
- * Copyright 2016 Linaro Ltd.
- */
-
-#ifndef __MODULE_H
-#define __MODULE_H
-
-struct gb_module {
- struct device dev;
- struct gb_host_device *hd;
-
- struct list_head hd_node;
-
- u8 module_id;
- size_t num_interfaces;
-
- bool disconnected;
-
- struct gb_interface *interfaces[0];
-};
-#define to_gb_module(d) container_of(d, struct gb_module, dev)
-
-struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id,
- size_t num_interfaces);
-int gb_module_add(struct gb_module *module);
-void gb_module_del(struct gb_module *module);
-void gb_module_put(struct gb_module *module);
-
-#endif /* __MODULE_H */
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
deleted file mode 100644
index fe268f7b63ed..000000000000
--- a/drivers/staging/greybus/operation.c
+++ /dev/null
@@ -1,1264 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus operations
- *
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-
-#include "greybus.h"
-#include "greybus_trace.h"
-
-static struct kmem_cache *gb_operation_cache;
-static struct kmem_cache *gb_message_cache;
-
-/* Workqueue to handle Greybus operation completions. */
-static struct workqueue_struct *gb_operation_completion_wq;
-
-/* Wait queue for synchronous cancellations. */
-static DECLARE_WAIT_QUEUE_HEAD(gb_operation_cancellation_queue);
-
-/*
- * Protects updates to operation->errno.
- */
-static DEFINE_SPINLOCK(gb_operations_lock);
-
-static int gb_operation_response_send(struct gb_operation *operation,
- int errno);
-
-/*
- * Increment operation active count and add to connection list unless the
- * connection is going away.
- *
- * Caller holds operation reference.
- */
-static int gb_operation_get_active(struct gb_operation *operation)
-{
- struct gb_connection *connection = operation->connection;
- unsigned long flags;
-
- spin_lock_irqsave(&connection->lock, flags);
- switch (connection->state) {
- case GB_CONNECTION_STATE_ENABLED:
- break;
- case GB_CONNECTION_STATE_ENABLED_TX:
- if (gb_operation_is_incoming(operation))
- goto err_unlock;
- break;
- case GB_CONNECTION_STATE_DISCONNECTING:
- if (!gb_operation_is_core(operation))
- goto err_unlock;
- break;
- default:
- goto err_unlock;
- }
-
- if (operation->active++ == 0)
- list_add_tail(&operation->links, &connection->operations);
-
- trace_gb_operation_get_active(operation);
-
- spin_unlock_irqrestore(&connection->lock, flags);
-
- return 0;
-
-err_unlock:
- spin_unlock_irqrestore(&connection->lock, flags);
-
- return -ENOTCONN;
-}
-
-/* Caller holds operation reference. */
-static void gb_operation_put_active(struct gb_operation *operation)
-{
- struct gb_connection *connection = operation->connection;
- unsigned long flags;
-
- spin_lock_irqsave(&connection->lock, flags);
-
- trace_gb_operation_put_active(operation);
-
- if (--operation->active == 0) {
- list_del(&operation->links);
- if (atomic_read(&operation->waiters))
- wake_up(&gb_operation_cancellation_queue);
- }
- spin_unlock_irqrestore(&connection->lock, flags);
-}
-
-static bool gb_operation_is_active(struct gb_operation *operation)
-{
- struct gb_connection *connection = operation->connection;
- unsigned long flags;
- bool ret;
-
- spin_lock_irqsave(&connection->lock, flags);
- ret = operation->active;
- spin_unlock_irqrestore(&connection->lock, flags);
-
- return ret;
-}
-
-/*
- * Set an operation's result.
- *
- * Initially an outgoing operation's errno value is -EBADR.
- * If no error occurs before sending the request message the only
- * valid value operation->errno can be set to is -EINPROGRESS,
- * indicating the request has been (or rather is about to be) sent.
- * At that point nobody should be looking at the result until the
- * response arrives.
- *
- * The first time the result gets set after the request has been
- * sent, that result "sticks." That is, if two concurrent threads
- * race to set the result, the first one wins. The return value
- * tells the caller whether its result was recorded; if not the
- * caller has nothing more to do.
- *
- * The result value -EILSEQ is reserved to signal an implementation
- * error; if it's ever observed, the code performing the request has
- * done something fundamentally wrong. It is an error to try to set
- * the result to -EBADR, and attempts to do so result in a warning,
- * and -EILSEQ is used instead. Similarly, the only valid result
- * value to set for an operation in initial state is -EINPROGRESS.
- * Attempts to do otherwise will also record a (successful) -EILSEQ
- * operation result.
- */
-static bool gb_operation_result_set(struct gb_operation *operation, int result)
-{
- unsigned long flags;
- int prev;
-
- if (result == -EINPROGRESS) {
- /*
- * -EINPROGRESS is used to indicate the request is
- * in flight. It should be the first result value
- * set after the initial -EBADR. Issue a warning
- * and record an implementation error if it's
- * set at any other time.
- */
- spin_lock_irqsave(&gb_operations_lock, flags);
- prev = operation->errno;
- if (prev == -EBADR)
- operation->errno = result;
- else
- operation->errno = -EILSEQ;
- spin_unlock_irqrestore(&gb_operations_lock, flags);
- WARN_ON(prev != -EBADR);
-
- return true;
- }
-
- /*
- * The first result value set after a request has been sent
- * will be the final result of the operation. Subsequent
- * attempts to set the result are ignored.
- *
- * Note that -EBADR is a reserved "initial state" result
- * value. Attempts to set this value result in a warning,
- * and the result code is set to -EILSEQ instead.
- */
- if (WARN_ON(result == -EBADR))
- result = -EILSEQ; /* Nobody should be setting -EBADR */
-
- spin_lock_irqsave(&gb_operations_lock, flags);
- prev = operation->errno;
- if (prev == -EINPROGRESS)
- operation->errno = result; /* First and final result */
- spin_unlock_irqrestore(&gb_operations_lock, flags);
-
- return prev == -EINPROGRESS;
-}
-
-int gb_operation_result(struct gb_operation *operation)
-{
- int result = operation->errno;
-
- WARN_ON(result == -EBADR);
- WARN_ON(result == -EINPROGRESS);
-
- return result;
-}
-EXPORT_SYMBOL_GPL(gb_operation_result);
-
-/*
- * Looks up an outgoing operation on a connection and returns a refcounted
- * pointer if found, or NULL otherwise.
- */
-static struct gb_operation *
-gb_operation_find_outgoing(struct gb_connection *connection, u16 operation_id)
-{
- struct gb_operation *operation;
- unsigned long flags;
- bool found = false;
-
- spin_lock_irqsave(&connection->lock, flags);
- list_for_each_entry(operation, &connection->operations, links)
- if (operation->id == operation_id &&
- !gb_operation_is_incoming(operation)) {
- gb_operation_get(operation);
- found = true;
- break;
- }
- spin_unlock_irqrestore(&connection->lock, flags);
-
- return found ? operation : NULL;
-}
-
-static int gb_message_send(struct gb_message *message, gfp_t gfp)
-{
- struct gb_connection *connection = message->operation->connection;
-
- trace_gb_message_send(message);
- return connection->hd->driver->message_send(connection->hd,
- connection->hd_cport_id,
- message,
- gfp);
-}
-
-/*
- * Cancel a message we have passed to the host device layer to be sent.
- */
-static void gb_message_cancel(struct gb_message *message)
-{
- struct gb_host_device *hd = message->operation->connection->hd;
-
- hd->driver->message_cancel(message);
-}
-
-static void gb_operation_request_handle(struct gb_operation *operation)
-{
- struct gb_connection *connection = operation->connection;
- int status;
- int ret;
-
- if (connection->handler) {
- status = connection->handler(operation);
- } else {
- dev_err(&connection->hd->dev,
- "%s: unexpected incoming request of type 0x%02x\n",
- connection->name, operation->type);
-
- status = -EPROTONOSUPPORT;
- }
-
- ret = gb_operation_response_send(operation, status);
- if (ret) {
- dev_err(&connection->hd->dev,
- "%s: failed to send response %d for type 0x%02x: %d\n",
- connection->name, status, operation->type, ret);
- return;
- }
-}
-
-/*
- * Process operation work.
- *
- * For incoming requests, call the protocol request handler. The operation
- * result should be -EINPROGRESS at this point.
- *
- * For outgoing requests, the operation result value should have
- * been set before queueing this. The operation callback function
- * allows the original requester to know the request has completed
- * and its result is available.
- */
-static void gb_operation_work(struct work_struct *work)
-{
- struct gb_operation *operation;
- int ret;
-
- operation = container_of(work, struct gb_operation, work);
-
- if (gb_operation_is_incoming(operation)) {
- gb_operation_request_handle(operation);
- } else {
- ret = del_timer_sync(&operation->timer);
- if (!ret) {
- /* Cancel request message if scheduled by timeout. */
- if (gb_operation_result(operation) == -ETIMEDOUT)
- gb_message_cancel(operation->request);
- }
-
- operation->callback(operation);
- }
-
- gb_operation_put_active(operation);
- gb_operation_put(operation);
-}
-
-static void gb_operation_timeout(struct timer_list *t)
-{
- struct gb_operation *operation = from_timer(operation, t, timer);
-
- if (gb_operation_result_set(operation, -ETIMEDOUT)) {
- /*
- * A stuck request message will be cancelled from the
- * workqueue.
- */
- queue_work(gb_operation_completion_wq, &operation->work);
- }
-}
-
-static void gb_operation_message_init(struct gb_host_device *hd,
- struct gb_message *message,
- u16 operation_id,
- size_t payload_size, u8 type)
-{
- struct gb_operation_msg_hdr *header;
-
- header = message->buffer;
-
- message->header = header;
- message->payload = payload_size ? header + 1 : NULL;
- message->payload_size = payload_size;
-
- /*
- * The type supplied for incoming message buffers will be
- * GB_REQUEST_TYPE_INVALID. Such buffers will be overwritten by
- * arriving data so there's no need to initialize the message header.
- */
- if (type != GB_REQUEST_TYPE_INVALID) {
- u16 message_size = (u16)(sizeof(*header) + payload_size);
-
- /*
- * For a request, the operation id gets filled in
- * when the message is sent. For a response, it
- * will be copied from the request by the caller.
- *
- * The result field in a request message must be
- * zero. It will be set just prior to sending for
- * a response.
- */
- header->size = cpu_to_le16(message_size);
- header->operation_id = 0;
- header->type = type;
- header->result = 0;
- }
-}
-
-/*
- * Allocate a message to be used for an operation request or response.
- * Both types of message contain a common header. The request message
- * for an outgoing operation is outbound, as is the response message
- * for an incoming operation. The message header for an outbound
- * message is partially initialized here.
- *
- * The headers for inbound messages don't need to be initialized;
- * they'll be filled in by arriving data.
- *
- * Our message buffers have the following layout:
- * message header \_ these combined are
- * message payload / the message size
- */
-static struct gb_message *
-gb_operation_message_alloc(struct gb_host_device *hd, u8 type,
- size_t payload_size, gfp_t gfp_flags)
-{
- struct gb_message *message;
- struct gb_operation_msg_hdr *header;
- size_t message_size = payload_size + sizeof(*header);
-
- if (message_size > hd->buffer_size_max) {
- dev_warn(&hd->dev, "requested message size too big (%zu > %zu)\n",
- message_size, hd->buffer_size_max);
- return NULL;
- }
-
- /* Allocate the message structure and buffer. */
- message = kmem_cache_zalloc(gb_message_cache, gfp_flags);
- if (!message)
- return NULL;
-
- message->buffer = kzalloc(message_size, gfp_flags);
- if (!message->buffer)
- goto err_free_message;
-
- /* Initialize the message. Operation id is filled in later. */
- gb_operation_message_init(hd, message, 0, payload_size, type);
-
- return message;
-
-err_free_message:
- kmem_cache_free(gb_message_cache, message);
-
- return NULL;
-}
-
-static void gb_operation_message_free(struct gb_message *message)
-{
- kfree(message->buffer);
- kmem_cache_free(gb_message_cache, message);
-}
-
-/*
- * Map an enum gb_operation_status value (which is represented in a
- * message as a single byte) to an appropriate Linux negative errno.
- */
-static int gb_operation_status_map(u8 status)
-{
- switch (status) {
- case GB_OP_SUCCESS:
- return 0;
- case GB_OP_INTERRUPTED:
- return -EINTR;
- case GB_OP_TIMEOUT:
- return -ETIMEDOUT;
- case GB_OP_NO_MEMORY:
- return -ENOMEM;
- case GB_OP_PROTOCOL_BAD:
- return -EPROTONOSUPPORT;
- case GB_OP_OVERFLOW:
- return -EMSGSIZE;
- case GB_OP_INVALID:
- return -EINVAL;
- case GB_OP_RETRY:
- return -EAGAIN;
- case GB_OP_NONEXISTENT:
- return -ENODEV;
- case GB_OP_MALFUNCTION:
- return -EILSEQ;
- case GB_OP_UNKNOWN_ERROR:
- default:
- return -EIO;
- }
-}
-
-/*
- * Map a Linux errno value (from operation->errno) into the value
- * that should represent it in a response message status sent
- * over the wire. Returns an enum gb_operation_status value (which
- * is represented in a message as a single byte).
- */
-static u8 gb_operation_errno_map(int errno)
-{
- switch (errno) {
- case 0:
- return GB_OP_SUCCESS;
- case -EINTR:
- return GB_OP_INTERRUPTED;
- case -ETIMEDOUT:
- return GB_OP_TIMEOUT;
- case -ENOMEM:
- return GB_OP_NO_MEMORY;
- case -EPROTONOSUPPORT:
- return GB_OP_PROTOCOL_BAD;
- case -EMSGSIZE:
- return GB_OP_OVERFLOW; /* Could be underflow too */
- case -EINVAL:
- return GB_OP_INVALID;
- case -EAGAIN:
- return GB_OP_RETRY;
- case -EILSEQ:
- return GB_OP_MALFUNCTION;
- case -ENODEV:
- return GB_OP_NONEXISTENT;
- case -EIO:
- default:
- return GB_OP_UNKNOWN_ERROR;
- }
-}
-
-bool gb_operation_response_alloc(struct gb_operation *operation,
- size_t response_size, gfp_t gfp)
-{
- struct gb_host_device *hd = operation->connection->hd;
- struct gb_operation_msg_hdr *request_header;
- struct gb_message *response;
- u8 type;
-
- type = operation->type | GB_MESSAGE_TYPE_RESPONSE;
- response = gb_operation_message_alloc(hd, type, response_size, gfp);
- if (!response)
- return false;
- response->operation = operation;
-
- /*
- * Size and type get initialized when the message is
- * allocated. The errno will be set before sending. All
- * that's left is the operation id, which we copy from the
- * request message header (as-is, in little-endian order).
- */
- request_header = operation->request->header;
- response->header->operation_id = request_header->operation_id;
- operation->response = response;
-
- return true;
-}
-EXPORT_SYMBOL_GPL(gb_operation_response_alloc);
-
-/*
- * Create a Greybus operation to be sent over the given connection.
- * The request buffer will be big enough for a payload of the given
- * size.
- *
- * For outgoing requests, the request message's header will be
- * initialized with the type of the request and the message size.
- * Outgoing operations must also specify the response buffer size,
- * which must be sufficient to hold all expected response data. The
- * response message header will eventually be overwritten, so there's
- * no need to initialize it here.
- *
- * Request messages for incoming operations can arrive in interrupt
- * context, so they must be allocated with GFP_ATOMIC. In this case
- * the request buffer will be immediately overwritten, so there is
- * no need to initialize the message header. Responsibility for
- * allocating a response buffer lies with the incoming request
- * handler for a protocol. So we don't allocate that here.
- *
- * Returns a pointer to the new operation or a null pointer if an
- * error occurs.
- */
-static struct gb_operation *
-gb_operation_create_common(struct gb_connection *connection, u8 type,
- size_t request_size, size_t response_size,
- unsigned long op_flags, gfp_t gfp_flags)
-{
- struct gb_host_device *hd = connection->hd;
- struct gb_operation *operation;
-
- operation = kmem_cache_zalloc(gb_operation_cache, gfp_flags);
- if (!operation)
- return NULL;
- operation->connection = connection;
-
- operation->request = gb_operation_message_alloc(hd, type, request_size,
- gfp_flags);
- if (!operation->request)
- goto err_cache;
- operation->request->operation = operation;
-
- /* Allocate the response buffer for outgoing operations */
- if (!(op_flags & GB_OPERATION_FLAG_INCOMING)) {
- if (!gb_operation_response_alloc(operation, response_size,
- gfp_flags)) {
- goto err_request;
- }
-
- timer_setup(&operation->timer, gb_operation_timeout, 0);
- }
-
- operation->flags = op_flags;
- operation->type = type;
- operation->errno = -EBADR; /* Initial value--means "never set" */
-
- INIT_WORK(&operation->work, gb_operation_work);
- init_completion(&operation->completion);
- kref_init(&operation->kref);
- atomic_set(&operation->waiters, 0);
-
- return operation;
-
-err_request:
- gb_operation_message_free(operation->request);
-err_cache:
- kmem_cache_free(gb_operation_cache, operation);
-
- return NULL;
-}
-
-/*
- * Create a new operation associated with the given connection. The
- * request and response sizes provided are the number of bytes
- * required to hold the request/response payload only. Both of
- * these are allowed to be 0. Note that 0x00 is reserved as an
- * invalid operation type for all protocols, and this is enforced
- * here.
- */
-struct gb_operation *
-gb_operation_create_flags(struct gb_connection *connection,
- u8 type, size_t request_size,
- size_t response_size, unsigned long flags,
- gfp_t gfp)
-{
- struct gb_operation *operation;
-
- if (WARN_ON_ONCE(type == GB_REQUEST_TYPE_INVALID))
- return NULL;
- if (WARN_ON_ONCE(type & GB_MESSAGE_TYPE_RESPONSE))
- type &= ~GB_MESSAGE_TYPE_RESPONSE;
-
- if (WARN_ON_ONCE(flags & ~GB_OPERATION_FLAG_USER_MASK))
- flags &= GB_OPERATION_FLAG_USER_MASK;
-
- operation = gb_operation_create_common(connection, type,
- request_size, response_size,
- flags, gfp);
- if (operation)
- trace_gb_operation_create(operation);
-
- return operation;
-}
-EXPORT_SYMBOL_GPL(gb_operation_create_flags);
-
-struct gb_operation *
-gb_operation_create_core(struct gb_connection *connection,
- u8 type, size_t request_size,
- size_t response_size, unsigned long flags,
- gfp_t gfp)
-{
- struct gb_operation *operation;
-
- flags |= GB_OPERATION_FLAG_CORE;
-
- operation = gb_operation_create_common(connection, type,
- request_size, response_size,
- flags, gfp);
- if (operation)
- trace_gb_operation_create_core(operation);
-
- return operation;
-}
-
-/* Do not export this function. */
-
-size_t gb_operation_get_payload_size_max(struct gb_connection *connection)
-{
- struct gb_host_device *hd = connection->hd;
-
- return hd->buffer_size_max - sizeof(struct gb_operation_msg_hdr);
-}
-EXPORT_SYMBOL_GPL(gb_operation_get_payload_size_max);
-
-static struct gb_operation *
-gb_operation_create_incoming(struct gb_connection *connection, u16 id,
- u8 type, void *data, size_t size)
-{
- struct gb_operation *operation;
- size_t request_size;
- unsigned long flags = GB_OPERATION_FLAG_INCOMING;
-
- /* Caller has made sure we at least have a message header. */
- request_size = size - sizeof(struct gb_operation_msg_hdr);
-
- if (!id)
- flags |= GB_OPERATION_FLAG_UNIDIRECTIONAL;
-
- operation = gb_operation_create_common(connection, type,
- request_size,
- GB_REQUEST_TYPE_INVALID,
- flags, GFP_ATOMIC);
- if (!operation)
- return NULL;
-
- operation->id = id;
- memcpy(operation->request->header, data, size);
- trace_gb_operation_create_incoming(operation);
-
- return operation;
-}
-
-/*
- * Get an additional reference on an operation.
- */
-void gb_operation_get(struct gb_operation *operation)
-{
- kref_get(&operation->kref);
-}
-EXPORT_SYMBOL_GPL(gb_operation_get);
-
-/*
- * Destroy a previously created operation.
- */
-static void _gb_operation_destroy(struct kref *kref)
-{
- struct gb_operation *operation;
-
- operation = container_of(kref, struct gb_operation, kref);
-
- trace_gb_operation_destroy(operation);
-
- if (operation->response)
- gb_operation_message_free(operation->response);
- gb_operation_message_free(operation->request);
-
- kmem_cache_free(gb_operation_cache, operation);
-}
-
-/*
- * Drop a reference on an operation, and destroy it when the last
- * one is gone.
- */
-void gb_operation_put(struct gb_operation *operation)
-{
- if (WARN_ON(!operation))
- return;
-
- kref_put(&operation->kref, _gb_operation_destroy);
-}
-EXPORT_SYMBOL_GPL(gb_operation_put);
-
-/* Tell the requester we're done */
-static void gb_operation_sync_callback(struct gb_operation *operation)
-{
- complete(&operation->completion);
-}
-
-/**
- * gb_operation_request_send() - send an operation request message
- * @operation: the operation to initiate
- * @callback: the operation completion callback
- * @timeout: operation timeout in milliseconds, or zero for no timeout
- * @gfp: the memory flags to use for any allocations
- *
- * The caller has filled in any payload so the request message is ready to go.
- * The callback function supplied will be called when the response message has
- * arrived, a unidirectional request has been sent, or the operation is
- * cancelled, indicating that the operation is complete. The callback function
- * can fetch the result of the operation using gb_operation_result() if
- * desired.
- *
- * Return: 0 if the request was successfully queued in the host-driver queues,
- * or a negative errno.
- */
-int gb_operation_request_send(struct gb_operation *operation,
- gb_operation_callback callback,
- unsigned int timeout,
- gfp_t gfp)
-{
- struct gb_connection *connection = operation->connection;
- struct gb_operation_msg_hdr *header;
- unsigned int cycle;
- int ret;
-
- if (gb_connection_is_offloaded(connection))
- return -EBUSY;
-
- if (!callback)
- return -EINVAL;
-
- /*
- * Record the callback function, which is executed in
- * non-atomic (workqueue) context when the final result
- * of an operation has been set.
- */
- operation->callback = callback;
-
- /*
- * Assign the operation's id, and store it in the request header.
- * Zero is a reserved operation id for unidirectional operations.
- */
- if (gb_operation_is_unidirectional(operation)) {
- operation->id = 0;
- } else {
- cycle = (unsigned int)atomic_inc_return(&connection->op_cycle);
- operation->id = (u16)(cycle % U16_MAX + 1);
- }
-
- header = operation->request->header;
- header->operation_id = cpu_to_le16(operation->id);
-
- gb_operation_result_set(operation, -EINPROGRESS);
-
- /*
- * Get an extra reference on the operation. It'll be dropped when the
- * operation completes.
- */
- gb_operation_get(operation);
- ret = gb_operation_get_active(operation);
- if (ret)
- goto err_put;
-
- ret = gb_message_send(operation->request, gfp);
- if (ret)
- goto err_put_active;
-
- if (timeout) {
- operation->timer.expires = jiffies + msecs_to_jiffies(timeout);
- add_timer(&operation->timer);
- }
-
- return 0;
-
-err_put_active:
- gb_operation_put_active(operation);
-err_put:
- gb_operation_put(operation);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_operation_request_send);
-
-/*
- * Send a synchronous operation. This function is expected to
- * block, returning only when the response has arrived, (or when an
- * error is detected. The return value is the result of the
- * operation.
- */
-int gb_operation_request_send_sync_timeout(struct gb_operation *operation,
- unsigned int timeout)
-{
- int ret;
-
- ret = gb_operation_request_send(operation, gb_operation_sync_callback,
- timeout, GFP_KERNEL);
- if (ret)
- return ret;
-
- ret = wait_for_completion_interruptible(&operation->completion);
- if (ret < 0) {
- /* Cancel the operation if interrupted */
- gb_operation_cancel(operation, -ECANCELED);
- }
-
- return gb_operation_result(operation);
-}
-EXPORT_SYMBOL_GPL(gb_operation_request_send_sync_timeout);
-
-/*
- * Send a response for an incoming operation request. A non-zero
- * errno indicates a failed operation.
- *
- * If there is any response payload, the incoming request handler is
- * responsible for allocating the response message. Otherwise the
- * it can simply supply the result errno; this function will
- * allocate the response message if necessary.
- */
-static int gb_operation_response_send(struct gb_operation *operation,
- int errno)
-{
- struct gb_connection *connection = operation->connection;
- int ret;
-
- if (!operation->response &&
- !gb_operation_is_unidirectional(operation)) {
- if (!gb_operation_response_alloc(operation, 0, GFP_KERNEL))
- return -ENOMEM;
- }
-
- /* Record the result */
- if (!gb_operation_result_set(operation, errno)) {
- dev_err(&connection->hd->dev, "request result already set\n");
- return -EIO; /* Shouldn't happen */
- }
-
- /* Sender of request does not care about response. */
- if (gb_operation_is_unidirectional(operation))
- return 0;
-
- /* Reference will be dropped when message has been sent. */
- gb_operation_get(operation);
- ret = gb_operation_get_active(operation);
- if (ret)
- goto err_put;
-
- /* Fill in the response header and send it */
- operation->response->header->result = gb_operation_errno_map(errno);
-
- ret = gb_message_send(operation->response, GFP_KERNEL);
- if (ret)
- goto err_put_active;
-
- return 0;
-
-err_put_active:
- gb_operation_put_active(operation);
-err_put:
- gb_operation_put(operation);
-
- return ret;
-}
-
-/*
- * This function is called when a message send request has completed.
- */
-void greybus_message_sent(struct gb_host_device *hd,
- struct gb_message *message, int status)
-{
- struct gb_operation *operation = message->operation;
- struct gb_connection *connection = operation->connection;
-
- /*
- * If the message was a response, we just need to drop our
- * reference to the operation. If an error occurred, report
- * it.
- *
- * For requests, if there's no error and the operation in not
- * unidirectional, there's nothing more to do until the response
- * arrives. If an error occurred attempting to send it, or if the
- * operation is unidrectional, record the result of the operation and
- * schedule its completion.
- */
- if (message == operation->response) {
- if (status) {
- dev_err(&connection->hd->dev,
- "%s: error sending response 0x%02x: %d\n",
- connection->name, operation->type, status);
- }
-
- gb_operation_put_active(operation);
- gb_operation_put(operation);
- } else if (status || gb_operation_is_unidirectional(operation)) {
- if (gb_operation_result_set(operation, status)) {
- queue_work(gb_operation_completion_wq,
- &operation->work);
- }
- }
-}
-EXPORT_SYMBOL_GPL(greybus_message_sent);
-
-/*
- * We've received data on a connection, and it doesn't look like a
- * response, so we assume it's a request.
- *
- * This is called in interrupt context, so just copy the incoming
- * data into the request buffer and handle the rest via workqueue.
- */
-static void gb_connection_recv_request(struct gb_connection *connection,
- const struct gb_operation_msg_hdr *header,
- void *data, size_t size)
-{
- struct gb_operation *operation;
- u16 operation_id;
- u8 type;
- int ret;
-
- operation_id = le16_to_cpu(header->operation_id);
- type = header->type;
-
- operation = gb_operation_create_incoming(connection, operation_id,
- type, data, size);
- if (!operation) {
- dev_err(&connection->hd->dev,
- "%s: can't create incoming operation\n",
- connection->name);
- return;
- }
-
- ret = gb_operation_get_active(operation);
- if (ret) {
- gb_operation_put(operation);
- return;
- }
- trace_gb_message_recv_request(operation->request);
-
- /*
- * The initial reference to the operation will be dropped when the
- * request handler returns.
- */
- if (gb_operation_result_set(operation, -EINPROGRESS))
- queue_work(connection->wq, &operation->work);
-}
-
-/*
- * We've received data that appears to be an operation response
- * message. Look up the operation, and record that we've received
- * its response.
- *
- * This is called in interrupt context, so just copy the incoming
- * data into the response buffer and handle the rest via workqueue.
- */
-static void gb_connection_recv_response(struct gb_connection *connection,
- const struct gb_operation_msg_hdr *header,
- void *data, size_t size)
-{
- struct gb_operation *operation;
- struct gb_message *message;
- size_t message_size;
- u16 operation_id;
- int errno;
-
- operation_id = le16_to_cpu(header->operation_id);
-
- if (!operation_id) {
- dev_err_ratelimited(&connection->hd->dev,
- "%s: invalid response id 0 received\n",
- connection->name);
- return;
- }
-
- operation = gb_operation_find_outgoing(connection, operation_id);
- if (!operation) {
- dev_err_ratelimited(&connection->hd->dev,
- "%s: unexpected response id 0x%04x received\n",
- connection->name, operation_id);
- return;
- }
-
- errno = gb_operation_status_map(header->result);
- message = operation->response;
- message_size = sizeof(*header) + message->payload_size;
- if (!errno && size > message_size) {
- dev_err_ratelimited(&connection->hd->dev,
- "%s: malformed response 0x%02x received (%zu > %zu)\n",
- connection->name, header->type,
- size, message_size);
- errno = -EMSGSIZE;
- } else if (!errno && size < message_size) {
- if (gb_operation_short_response_allowed(operation)) {
- message->payload_size = size - sizeof(*header);
- } else {
- dev_err_ratelimited(&connection->hd->dev,
- "%s: short response 0x%02x received (%zu < %zu)\n",
- connection->name, header->type,
- size, message_size);
- errno = -EMSGSIZE;
- }
- }
-
- /* We must ignore the payload if a bad status is returned */
- if (errno)
- size = sizeof(*header);
-
- /* The rest will be handled in work queue context */
- if (gb_operation_result_set(operation, errno)) {
- memcpy(message->buffer, data, size);
-
- trace_gb_message_recv_response(message);
-
- queue_work(gb_operation_completion_wq, &operation->work);
- }
-
- gb_operation_put(operation);
-}
-
-/*
- * Handle data arriving on a connection. As soon as we return the
- * supplied data buffer will be reused (so unless we do something
- * with, it's effectively dropped).
- */
-void gb_connection_recv(struct gb_connection *connection,
- void *data, size_t size)
-{
- struct gb_operation_msg_hdr header;
- struct device *dev = &connection->hd->dev;
- size_t msg_size;
-
- if (connection->state == GB_CONNECTION_STATE_DISABLED ||
- gb_connection_is_offloaded(connection)) {
- dev_warn_ratelimited(dev, "%s: dropping %zu received bytes\n",
- connection->name, size);
- return;
- }
-
- if (size < sizeof(header)) {
- dev_err_ratelimited(dev, "%s: short message received\n",
- connection->name);
- return;
- }
-
- /* Use memcpy as data may be unaligned */
- memcpy(&header, data, sizeof(header));
- msg_size = le16_to_cpu(header.size);
- if (size < msg_size) {
- dev_err_ratelimited(dev,
- "%s: incomplete message 0x%04x of type 0x%02x received (%zu < %zu)\n",
- connection->name,
- le16_to_cpu(header.operation_id),
- header.type, size, msg_size);
- return; /* XXX Should still complete operation */
- }
-
- if (header.type & GB_MESSAGE_TYPE_RESPONSE) {
- gb_connection_recv_response(connection, &header, data,
- msg_size);
- } else {
- gb_connection_recv_request(connection, &header, data,
- msg_size);
- }
-}
-
-/*
- * Cancel an outgoing operation synchronously, and record the given error to
- * indicate why.
- */
-void gb_operation_cancel(struct gb_operation *operation, int errno)
-{
- if (WARN_ON(gb_operation_is_incoming(operation)))
- return;
-
- if (gb_operation_result_set(operation, errno)) {
- gb_message_cancel(operation->request);
- queue_work(gb_operation_completion_wq, &operation->work);
- }
- trace_gb_message_cancel_outgoing(operation->request);
-
- atomic_inc(&operation->waiters);
- wait_event(gb_operation_cancellation_queue,
- !gb_operation_is_active(operation));
- atomic_dec(&operation->waiters);
-}
-EXPORT_SYMBOL_GPL(gb_operation_cancel);
-
-/*
- * Cancel an incoming operation synchronously. Called during connection tear
- * down.
- */
-void gb_operation_cancel_incoming(struct gb_operation *operation, int errno)
-{
- if (WARN_ON(!gb_operation_is_incoming(operation)))
- return;
-
- if (!gb_operation_is_unidirectional(operation)) {
- /*
- * Make sure the request handler has submitted the response
- * before cancelling it.
- */
- flush_work(&operation->work);
- if (!gb_operation_result_set(operation, errno))
- gb_message_cancel(operation->response);
- }
- trace_gb_message_cancel_incoming(operation->response);
-
- atomic_inc(&operation->waiters);
- wait_event(gb_operation_cancellation_queue,
- !gb_operation_is_active(operation));
- atomic_dec(&operation->waiters);
-}
-
-/**
- * gb_operation_sync_timeout() - implement a "simple" synchronous operation
- * @connection: the Greybus connection to send this to
- * @type: the type of operation to send
- * @request: pointer to a memory buffer to copy the request from
- * @request_size: size of @request
- * @response: pointer to a memory buffer to copy the response to
- * @response_size: the size of @response.
- * @timeout: operation timeout in milliseconds
- *
- * This function implements a simple synchronous Greybus operation. It sends
- * the provided operation request and waits (sleeps) until the corresponding
- * operation response message has been successfully received, or an error
- * occurs. @request and @response are buffers to hold the request and response
- * data respectively, and if they are not NULL, their size must be specified in
- * @request_size and @response_size.
- *
- * If a response payload is to come back, and @response is not NULL,
- * @response_size number of bytes will be copied into @response if the operation
- * is successful.
- *
- * If there is an error, the response buffer is left alone.
- */
-int gb_operation_sync_timeout(struct gb_connection *connection, int type,
- void *request, int request_size,
- void *response, int response_size,
- unsigned int timeout)
-{
- struct gb_operation *operation;
- int ret;
-
- if ((response_size && !response) ||
- (request_size && !request))
- return -EINVAL;
-
- operation = gb_operation_create(connection, type,
- request_size, response_size,
- GFP_KERNEL);
- if (!operation)
- return -ENOMEM;
-
- if (request_size)
- memcpy(operation->request->payload, request, request_size);
-
- ret = gb_operation_request_send_sync_timeout(operation, timeout);
- if (ret) {
- dev_err(&connection->hd->dev,
- "%s: synchronous operation id 0x%04x of type 0x%02x failed: %d\n",
- connection->name, operation->id, type, ret);
- } else {
- if (response_size) {
- memcpy(response, operation->response->payload,
- response_size);
- }
- }
-
- gb_operation_put(operation);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_operation_sync_timeout);
-
-/**
- * gb_operation_unidirectional_timeout() - initiate a unidirectional operation
- * @connection: connection to use
- * @type: type of operation to send
- * @request: memory buffer to copy the request from
- * @request_size: size of @request
- * @timeout: send timeout in milliseconds
- *
- * Initiate a unidirectional operation by sending a request message and
- * waiting for it to be acknowledged as sent by the host device.
- *
- * Note that successful send of a unidirectional operation does not imply that
- * the request as actually reached the remote end of the connection.
- */
-int gb_operation_unidirectional_timeout(struct gb_connection *connection,
- int type, void *request,
- int request_size,
- unsigned int timeout)
-{
- struct gb_operation *operation;
- int ret;
-
- if (request_size && !request)
- return -EINVAL;
-
- operation = gb_operation_create_flags(connection, type,
- request_size, 0,
- GB_OPERATION_FLAG_UNIDIRECTIONAL,
- GFP_KERNEL);
- if (!operation)
- return -ENOMEM;
-
- if (request_size)
- memcpy(operation->request->payload, request, request_size);
-
- ret = gb_operation_request_send_sync_timeout(operation, timeout);
- if (ret) {
- dev_err(&connection->hd->dev,
- "%s: unidirectional operation of type 0x%02x failed: %d\n",
- connection->name, type, ret);
- }
-
- gb_operation_put(operation);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_operation_unidirectional_timeout);
-
-int __init gb_operation_init(void)
-{
- gb_message_cache = kmem_cache_create("gb_message_cache",
- sizeof(struct gb_message), 0, 0,
- NULL);
- if (!gb_message_cache)
- return -ENOMEM;
-
- gb_operation_cache = kmem_cache_create("gb_operation_cache",
- sizeof(struct gb_operation), 0,
- 0, NULL);
- if (!gb_operation_cache)
- goto err_destroy_message_cache;
-
- gb_operation_completion_wq = alloc_workqueue("greybus_completion",
- 0, 0);
- if (!gb_operation_completion_wq)
- goto err_destroy_operation_cache;
-
- return 0;
-
-err_destroy_operation_cache:
- kmem_cache_destroy(gb_operation_cache);
- gb_operation_cache = NULL;
-err_destroy_message_cache:
- kmem_cache_destroy(gb_message_cache);
- gb_message_cache = NULL;
-
- return -ENOMEM;
-}
-
-void gb_operation_exit(void)
-{
- destroy_workqueue(gb_operation_completion_wq);
- gb_operation_completion_wq = NULL;
- kmem_cache_destroy(gb_operation_cache);
- gb_operation_cache = NULL;
- kmem_cache_destroy(gb_message_cache);
- gb_message_cache = NULL;
-}
diff --git a/drivers/staging/greybus/operation.h b/drivers/staging/greybus/operation.h
deleted file mode 100644
index 40b7b02fff88..000000000000
--- a/drivers/staging/greybus/operation.h
+++ /dev/null
@@ -1,224 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus operations
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- */
-
-#ifndef __OPERATION_H
-#define __OPERATION_H
-
-#include <linux/completion.h>
-
-struct gb_operation;
-
-/* The default amount of time a request is given to complete */
-#define GB_OPERATION_TIMEOUT_DEFAULT 1000 /* milliseconds */
-
-/*
- * The top bit of the type in an operation message header indicates
- * whether the message is a request (bit clear) or response (bit set)
- */
-#define GB_MESSAGE_TYPE_RESPONSE ((u8)0x80)
-
-enum gb_operation_result {
- GB_OP_SUCCESS = 0x00,
- GB_OP_INTERRUPTED = 0x01,
- GB_OP_TIMEOUT = 0x02,
- GB_OP_NO_MEMORY = 0x03,
- GB_OP_PROTOCOL_BAD = 0x04,
- GB_OP_OVERFLOW = 0x05,
- GB_OP_INVALID = 0x06,
- GB_OP_RETRY = 0x07,
- GB_OP_NONEXISTENT = 0x08,
- GB_OP_UNKNOWN_ERROR = 0xfe,
- GB_OP_MALFUNCTION = 0xff,
-};
-
-#define GB_OPERATION_MESSAGE_SIZE_MIN sizeof(struct gb_operation_msg_hdr)
-#define GB_OPERATION_MESSAGE_SIZE_MAX U16_MAX
-
-/*
- * Protocol code should only examine the payload and payload_size fields, and
- * host-controller drivers may use the hcpriv field. All other fields are
- * intended to be private to the operations core code.
- */
-struct gb_message {
- struct gb_operation *operation;
- struct gb_operation_msg_hdr *header;
-
- void *payload;
- size_t payload_size;
-
- void *buffer;
-
- void *hcpriv;
-};
-
-#define GB_OPERATION_FLAG_INCOMING BIT(0)
-#define GB_OPERATION_FLAG_UNIDIRECTIONAL BIT(1)
-#define GB_OPERATION_FLAG_SHORT_RESPONSE BIT(2)
-#define GB_OPERATION_FLAG_CORE BIT(3)
-
-#define GB_OPERATION_FLAG_USER_MASK (GB_OPERATION_FLAG_SHORT_RESPONSE | \
- GB_OPERATION_FLAG_UNIDIRECTIONAL)
-
-/*
- * A Greybus operation is a remote procedure call performed over a
- * connection between two UniPro interfaces.
- *
- * Every operation consists of a request message sent to the other
- * end of the connection coupled with a reply message returned to
- * the sender. Every operation has a type, whose interpretation is
- * dependent on the protocol associated with the connection.
- *
- * Only four things in an operation structure are intended to be
- * directly usable by protocol handlers: the operation's connection
- * pointer; the operation type; the request message payload (and
- * size); and the response message payload (and size). Note that a
- * message with a 0-byte payload has a null message payload pointer.
- *
- * In addition, every operation has a result, which is an errno
- * value. Protocol handlers access the operation result using
- * gb_operation_result().
- */
-typedef void (*gb_operation_callback)(struct gb_operation *);
-struct gb_operation {
- struct gb_connection *connection;
- struct gb_message *request;
- struct gb_message *response;
-
- unsigned long flags;
- u8 type;
- u16 id;
- int errno; /* Operation result */
-
- struct work_struct work;
- gb_operation_callback callback;
- struct completion completion;
- struct timer_list timer;
-
- struct kref kref;
- atomic_t waiters;
-
- int active;
- struct list_head links; /* connection->operations */
-
- void *private;
-};
-
-static inline bool
-gb_operation_is_incoming(struct gb_operation *operation)
-{
- return operation->flags & GB_OPERATION_FLAG_INCOMING;
-}
-
-static inline bool
-gb_operation_is_unidirectional(struct gb_operation *operation)
-{
- return operation->flags & GB_OPERATION_FLAG_UNIDIRECTIONAL;
-}
-
-static inline bool
-gb_operation_short_response_allowed(struct gb_operation *operation)
-{
- return operation->flags & GB_OPERATION_FLAG_SHORT_RESPONSE;
-}
-
-static inline bool gb_operation_is_core(struct gb_operation *operation)
-{
- return operation->flags & GB_OPERATION_FLAG_CORE;
-}
-
-void gb_connection_recv(struct gb_connection *connection,
- void *data, size_t size);
-
-int gb_operation_result(struct gb_operation *operation);
-
-size_t gb_operation_get_payload_size_max(struct gb_connection *connection);
-struct gb_operation *
-gb_operation_create_flags(struct gb_connection *connection,
- u8 type, size_t request_size,
- size_t response_size, unsigned long flags,
- gfp_t gfp);
-
-static inline struct gb_operation *
-gb_operation_create(struct gb_connection *connection,
- u8 type, size_t request_size,
- size_t response_size, gfp_t gfp)
-{
- return gb_operation_create_flags(connection, type, request_size,
- response_size, 0, gfp);
-}
-
-struct gb_operation *
-gb_operation_create_core(struct gb_connection *connection,
- u8 type, size_t request_size,
- size_t response_size, unsigned long flags,
- gfp_t gfp);
-
-void gb_operation_get(struct gb_operation *operation);
-void gb_operation_put(struct gb_operation *operation);
-
-bool gb_operation_response_alloc(struct gb_operation *operation,
- size_t response_size, gfp_t gfp);
-
-int gb_operation_request_send(struct gb_operation *operation,
- gb_operation_callback callback,
- unsigned int timeout,
- gfp_t gfp);
-int gb_operation_request_send_sync_timeout(struct gb_operation *operation,
- unsigned int timeout);
-static inline int
-gb_operation_request_send_sync(struct gb_operation *operation)
-{
- return gb_operation_request_send_sync_timeout(operation,
- GB_OPERATION_TIMEOUT_DEFAULT);
-}
-
-void gb_operation_cancel(struct gb_operation *operation, int errno);
-void gb_operation_cancel_incoming(struct gb_operation *operation, int errno);
-
-void greybus_message_sent(struct gb_host_device *hd,
- struct gb_message *message, int status);
-
-int gb_operation_sync_timeout(struct gb_connection *connection, int type,
- void *request, int request_size,
- void *response, int response_size,
- unsigned int timeout);
-int gb_operation_unidirectional_timeout(struct gb_connection *connection,
- int type, void *request, int request_size,
- unsigned int timeout);
-
-static inline int gb_operation_sync(struct gb_connection *connection, int type,
- void *request, int request_size,
- void *response, int response_size)
-{
- return gb_operation_sync_timeout(connection, type,
- request, request_size, response, response_size,
- GB_OPERATION_TIMEOUT_DEFAULT);
-}
-
-static inline int gb_operation_unidirectional(struct gb_connection *connection,
- int type, void *request, int request_size)
-{
- return gb_operation_unidirectional_timeout(connection, type,
- request, request_size, GB_OPERATION_TIMEOUT_DEFAULT);
-}
-
-static inline void *gb_operation_get_data(struct gb_operation *operation)
-{
- return operation->private;
-}
-
-static inline void gb_operation_set_data(struct gb_operation *operation,
- void *data)
-{
- operation->private = data;
-}
-
-int gb_operation_init(void);
-void gb_operation_exit(void);
-
-#endif /* !__OPERATION_H */
diff --git a/drivers/staging/greybus/power_supply.c b/drivers/staging/greybus/power_supply.c
index 34b40a409ea3..ec96f28887f9 100644
--- a/drivers/staging/greybus/power_supply.c
+++ b/drivers/staging/greybus/power_supply.c
@@ -10,8 +10,7 @@
#include <linux/module.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
-
-#include "greybus.h"
+#include <linux/greybus.h>
#define PROP_MAX 32
diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c
index 4a6d394b6c44..891a6a672378 100644
--- a/drivers/staging/greybus/pwm.c
+++ b/drivers/staging/greybus/pwm.c
@@ -10,8 +10,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pwm.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "gbphy.h"
struct gb_pwm_chip {
diff --git a/drivers/staging/greybus/raw.c b/drivers/staging/greybus/raw.c
index 838acbe84ca0..64a17dfe3b6e 100644
--- a/drivers/staging/greybus/raw.c
+++ b/drivers/staging/greybus/raw.c
@@ -13,8 +13,7 @@
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/uaccess.h>
-
-#include "greybus.h"
+#include <linux/greybus.h>
struct gb_raw {
struct gb_connection *connection;
diff --git a/drivers/staging/greybus/sdio.c b/drivers/staging/greybus/sdio.c
index a097a8916b3b..68c5718be827 100644
--- a/drivers/staging/greybus/sdio.c
+++ b/drivers/staging/greybus/sdio.c
@@ -12,8 +12,8 @@
#include <linux/mmc/mmc.h>
#include <linux/scatterlist.h>
#include <linux/workqueue.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "gbphy.h"
struct gb_sdio_host {
diff --git a/drivers/staging/greybus/spi.c b/drivers/staging/greybus/spi.c
index 47d896992b35..68e8d272db6d 100644
--- a/drivers/staging/greybus/spi.c
+++ b/drivers/staging/greybus/spi.c
@@ -7,8 +7,8 @@
*/
#include <linux/module.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "gbphy.h"
#include "spilib.h"
diff --git a/drivers/staging/greybus/spilib.c b/drivers/staging/greybus/spilib.c
index 2e07c6b41334..fc27c52de74a 100644
--- a/drivers/staging/greybus/spilib.c
+++ b/drivers/staging/greybus/spilib.c
@@ -10,9 +10,9 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/greybus.h>
#include <linux/spi/spi.h>
-#include "greybus.h"
#include "spilib.h"
struct gb_spilib {
diff --git a/drivers/staging/greybus/spilib.h b/drivers/staging/greybus/spilib.h
index 043d4d32c3ee..9d416839e3be 100644
--- a/drivers/staging/greybus/spilib.h
+++ b/drivers/staging/greybus/spilib.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Greybus SPI library header
*
diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c
deleted file mode 100644
index 05bc45287b87..000000000000
--- a/drivers/staging/greybus/svc.c
+++ /dev/null
@@ -1,1398 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * SVC Greybus driver.
- *
- * Copyright 2015 Google Inc.
- * Copyright 2015 Linaro Ltd.
- */
-
-#include <linux/debugfs.h>
-#include <linux/workqueue.h>
-
-#include "greybus.h"
-
-#define SVC_INTF_EJECT_TIMEOUT 9000
-#define SVC_INTF_ACTIVATE_TIMEOUT 6000
-#define SVC_INTF_RESUME_TIMEOUT 3000
-
-struct gb_svc_deferred_request {
- struct work_struct work;
- struct gb_operation *operation;
-};
-
-static int gb_svc_queue_deferred_request(struct gb_operation *operation);
-
-static ssize_t endo_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_svc *svc = to_gb_svc(dev);
-
- return sprintf(buf, "0x%04x\n", svc->endo_id);
-}
-static DEVICE_ATTR_RO(endo_id);
-
-static ssize_t ap_intf_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_svc *svc = to_gb_svc(dev);
-
- return sprintf(buf, "%u\n", svc->ap_intf_id);
-}
-static DEVICE_ATTR_RO(ap_intf_id);
-
-// FIXME
-// This is a hack, we need to do this "right" and clean the interface up
-// properly, not just forcibly yank the thing out of the system and hope for the
-// best. But for now, people want their modules to come out without having to
-// throw the thing to the ground or get out a screwdriver.
-static ssize_t intf_eject_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t len)
-{
- struct gb_svc *svc = to_gb_svc(dev);
- unsigned short intf_id;
- int ret;
-
- ret = kstrtou16(buf, 10, &intf_id);
- if (ret < 0)
- return ret;
-
- dev_warn(dev, "Forcibly trying to eject interface %d\n", intf_id);
-
- ret = gb_svc_intf_eject(svc, intf_id);
- if (ret < 0)
- return ret;
-
- return len;
-}
-static DEVICE_ATTR_WO(intf_eject);
-
-static ssize_t watchdog_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct gb_svc *svc = to_gb_svc(dev);
-
- return sprintf(buf, "%s\n",
- gb_svc_watchdog_enabled(svc) ? "enabled" : "disabled");
-}
-
-static ssize_t watchdog_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t len)
-{
- struct gb_svc *svc = to_gb_svc(dev);
- int retval;
- bool user_request;
-
- retval = strtobool(buf, &user_request);
- if (retval)
- return retval;
-
- if (user_request)
- retval = gb_svc_watchdog_enable(svc);
- else
- retval = gb_svc_watchdog_disable(svc);
- if (retval)
- return retval;
- return len;
-}
-static DEVICE_ATTR_RW(watchdog);
-
-static ssize_t watchdog_action_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gb_svc *svc = to_gb_svc(dev);
-
- if (svc->action == GB_SVC_WATCHDOG_BITE_PANIC_KERNEL)
- return sprintf(buf, "panic\n");
- else if (svc->action == GB_SVC_WATCHDOG_BITE_RESET_UNIPRO)
- return sprintf(buf, "reset\n");
-
- return -EINVAL;
-}
-
-static ssize_t watchdog_action_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct gb_svc *svc = to_gb_svc(dev);
-
- if (sysfs_streq(buf, "panic"))
- svc->action = GB_SVC_WATCHDOG_BITE_PANIC_KERNEL;
- else if (sysfs_streq(buf, "reset"))
- svc->action = GB_SVC_WATCHDOG_BITE_RESET_UNIPRO;
- else
- return -EINVAL;
-
- return len;
-}
-static DEVICE_ATTR_RW(watchdog_action);
-
-static int gb_svc_pwrmon_rail_count_get(struct gb_svc *svc, u8 *value)
-{
- struct gb_svc_pwrmon_rail_count_get_response response;
- int ret;
-
- ret = gb_operation_sync(svc->connection,
- GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET, NULL, 0,
- &response, sizeof(response));
- if (ret) {
- dev_err(&svc->dev, "failed to get rail count: %d\n", ret);
- return ret;
- }
-
- *value = response.rail_count;
-
- return 0;
-}
-
-static int gb_svc_pwrmon_rail_names_get(struct gb_svc *svc,
- struct gb_svc_pwrmon_rail_names_get_response *response,
- size_t bufsize)
-{
- int ret;
-
- ret = gb_operation_sync(svc->connection,
- GB_SVC_TYPE_PWRMON_RAIL_NAMES_GET, NULL, 0,
- response, bufsize);
- if (ret) {
- dev_err(&svc->dev, "failed to get rail names: %d\n", ret);
- return ret;
- }
-
- if (response->status != GB_SVC_OP_SUCCESS) {
- dev_err(&svc->dev,
- "SVC error while getting rail names: %u\n",
- response->status);
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static int gb_svc_pwrmon_sample_get(struct gb_svc *svc, u8 rail_id,
- u8 measurement_type, u32 *value)
-{
- struct gb_svc_pwrmon_sample_get_request request;
- struct gb_svc_pwrmon_sample_get_response response;
- int ret;
-
- request.rail_id = rail_id;
- request.measurement_type = measurement_type;
-
- ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_PWRMON_SAMPLE_GET,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret) {
- dev_err(&svc->dev, "failed to get rail sample: %d\n", ret);
- return ret;
- }
-
- if (response.result) {
- dev_err(&svc->dev,
- "UniPro error while getting rail power sample (%d %d): %d\n",
- rail_id, measurement_type, response.result);
- switch (response.result) {
- case GB_SVC_PWRMON_GET_SAMPLE_INVAL:
- return -EINVAL;
- case GB_SVC_PWRMON_GET_SAMPLE_NOSUPP:
- return -ENOMSG;
- default:
- return -EREMOTEIO;
- }
- }
-
- *value = le32_to_cpu(response.measurement);
-
- return 0;
-}
-
-int gb_svc_pwrmon_intf_sample_get(struct gb_svc *svc, u8 intf_id,
- u8 measurement_type, u32 *value)
-{
- struct gb_svc_pwrmon_intf_sample_get_request request;
- struct gb_svc_pwrmon_intf_sample_get_response response;
- int ret;
-
- request.intf_id = intf_id;
- request.measurement_type = measurement_type;
-
- ret = gb_operation_sync(svc->connection,
- GB_SVC_TYPE_PWRMON_INTF_SAMPLE_GET,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret) {
- dev_err(&svc->dev, "failed to get intf sample: %d\n", ret);
- return ret;
- }
-
- if (response.result) {
- dev_err(&svc->dev,
- "UniPro error while getting intf power sample (%d %d): %d\n",
- intf_id, measurement_type, response.result);
- switch (response.result) {
- case GB_SVC_PWRMON_GET_SAMPLE_INVAL:
- return -EINVAL;
- case GB_SVC_PWRMON_GET_SAMPLE_NOSUPP:
- return -ENOMSG;
- default:
- return -EREMOTEIO;
- }
- }
-
- *value = le32_to_cpu(response.measurement);
-
- return 0;
-}
-
-static struct attribute *svc_attrs[] = {
- &dev_attr_endo_id.attr,
- &dev_attr_ap_intf_id.attr,
- &dev_attr_intf_eject.attr,
- &dev_attr_watchdog.attr,
- &dev_attr_watchdog_action.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(svc);
-
-int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
-{
- struct gb_svc_intf_device_id_request request;
-
- request.intf_id = intf_id;
- request.device_id = device_id;
-
- return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_DEVICE_ID,
- &request, sizeof(request), NULL, 0);
-}
-
-int gb_svc_intf_eject(struct gb_svc *svc, u8 intf_id)
-{
- struct gb_svc_intf_eject_request request;
- int ret;
-
- request.intf_id = intf_id;
-
- /*
- * The pulse width for module release in svc is long so we need to
- * increase the timeout so the operation will not return to soon.
- */
- ret = gb_operation_sync_timeout(svc->connection,
- GB_SVC_TYPE_INTF_EJECT, &request,
- sizeof(request), NULL, 0,
- SVC_INTF_EJECT_TIMEOUT);
- if (ret) {
- dev_err(&svc->dev, "failed to eject interface %u\n", intf_id);
- return ret;
- }
-
- return 0;
-}
-
-int gb_svc_intf_vsys_set(struct gb_svc *svc, u8 intf_id, bool enable)
-{
- struct gb_svc_intf_vsys_request request;
- struct gb_svc_intf_vsys_response response;
- int type, ret;
-
- request.intf_id = intf_id;
-
- if (enable)
- type = GB_SVC_TYPE_INTF_VSYS_ENABLE;
- else
- type = GB_SVC_TYPE_INTF_VSYS_DISABLE;
-
- ret = gb_operation_sync(svc->connection, type,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret < 0)
- return ret;
- if (response.result_code != GB_SVC_INTF_VSYS_OK)
- return -EREMOTEIO;
- return 0;
-}
-
-int gb_svc_intf_refclk_set(struct gb_svc *svc, u8 intf_id, bool enable)
-{
- struct gb_svc_intf_refclk_request request;
- struct gb_svc_intf_refclk_response response;
- int type, ret;
-
- request.intf_id = intf_id;
-
- if (enable)
- type = GB_SVC_TYPE_INTF_REFCLK_ENABLE;
- else
- type = GB_SVC_TYPE_INTF_REFCLK_DISABLE;
-
- ret = gb_operation_sync(svc->connection, type,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret < 0)
- return ret;
- if (response.result_code != GB_SVC_INTF_REFCLK_OK)
- return -EREMOTEIO;
- return 0;
-}
-
-int gb_svc_intf_unipro_set(struct gb_svc *svc, u8 intf_id, bool enable)
-{
- struct gb_svc_intf_unipro_request request;
- struct gb_svc_intf_unipro_response response;
- int type, ret;
-
- request.intf_id = intf_id;
-
- if (enable)
- type = GB_SVC_TYPE_INTF_UNIPRO_ENABLE;
- else
- type = GB_SVC_TYPE_INTF_UNIPRO_DISABLE;
-
- ret = gb_operation_sync(svc->connection, type,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret < 0)
- return ret;
- if (response.result_code != GB_SVC_INTF_UNIPRO_OK)
- return -EREMOTEIO;
- return 0;
-}
-
-int gb_svc_intf_activate(struct gb_svc *svc, u8 intf_id, u8 *intf_type)
-{
- struct gb_svc_intf_activate_request request;
- struct gb_svc_intf_activate_response response;
- int ret;
-
- request.intf_id = intf_id;
-
- ret = gb_operation_sync_timeout(svc->connection,
- GB_SVC_TYPE_INTF_ACTIVATE,
- &request, sizeof(request),
- &response, sizeof(response),
- SVC_INTF_ACTIVATE_TIMEOUT);
- if (ret < 0)
- return ret;
- if (response.status != GB_SVC_OP_SUCCESS) {
- dev_err(&svc->dev, "failed to activate interface %u: %u\n",
- intf_id, response.status);
- return -EREMOTEIO;
- }
-
- *intf_type = response.intf_type;
-
- return 0;
-}
-
-int gb_svc_intf_resume(struct gb_svc *svc, u8 intf_id)
-{
- struct gb_svc_intf_resume_request request;
- struct gb_svc_intf_resume_response response;
- int ret;
-
- request.intf_id = intf_id;
-
- ret = gb_operation_sync_timeout(svc->connection,
- GB_SVC_TYPE_INTF_RESUME,
- &request, sizeof(request),
- &response, sizeof(response),
- SVC_INTF_RESUME_TIMEOUT);
- if (ret < 0) {
- dev_err(&svc->dev, "failed to send interface resume %u: %d\n",
- intf_id, ret);
- return ret;
- }
-
- if (response.status != GB_SVC_OP_SUCCESS) {
- dev_err(&svc->dev, "failed to resume interface %u: %u\n",
- intf_id, response.status);
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-int gb_svc_dme_peer_get(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
- u32 *value)
-{
- struct gb_svc_dme_peer_get_request request;
- struct gb_svc_dme_peer_get_response response;
- u16 result;
- int ret;
-
- request.intf_id = intf_id;
- request.attr = cpu_to_le16(attr);
- request.selector = cpu_to_le16(selector);
-
- ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_DME_PEER_GET,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret) {
- dev_err(&svc->dev, "failed to get DME attribute (%u 0x%04x %u): %d\n",
- intf_id, attr, selector, ret);
- return ret;
- }
-
- result = le16_to_cpu(response.result_code);
- if (result) {
- dev_err(&svc->dev, "UniPro error while getting DME attribute (%u 0x%04x %u): %u\n",
- intf_id, attr, selector, result);
- return -EREMOTEIO;
- }
-
- if (value)
- *value = le32_to_cpu(response.attr_value);
-
- return 0;
-}
-
-int gb_svc_dme_peer_set(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
- u32 value)
-{
- struct gb_svc_dme_peer_set_request request;
- struct gb_svc_dme_peer_set_response response;
- u16 result;
- int ret;
-
- request.intf_id = intf_id;
- request.attr = cpu_to_le16(attr);
- request.selector = cpu_to_le16(selector);
- request.value = cpu_to_le32(value);
-
- ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_DME_PEER_SET,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret) {
- dev_err(&svc->dev, "failed to set DME attribute (%u 0x%04x %u %u): %d\n",
- intf_id, attr, selector, value, ret);
- return ret;
- }
-
- result = le16_to_cpu(response.result_code);
- if (result) {
- dev_err(&svc->dev, "UniPro error while setting DME attribute (%u 0x%04x %u %u): %u\n",
- intf_id, attr, selector, value, result);
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-int gb_svc_connection_create(struct gb_svc *svc,
- u8 intf1_id, u16 cport1_id,
- u8 intf2_id, u16 cport2_id,
- u8 cport_flags)
-{
- struct gb_svc_conn_create_request request;
-
- request.intf1_id = intf1_id;
- request.cport1_id = cpu_to_le16(cport1_id);
- request.intf2_id = intf2_id;
- request.cport2_id = cpu_to_le16(cport2_id);
- request.tc = 0; /* TC0 */
- request.flags = cport_flags;
-
- return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
- &request, sizeof(request), NULL, 0);
-}
-
-void gb_svc_connection_destroy(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
- u8 intf2_id, u16 cport2_id)
-{
- struct gb_svc_conn_destroy_request request;
- struct gb_connection *connection = svc->connection;
- int ret;
-
- request.intf1_id = intf1_id;
- request.cport1_id = cpu_to_le16(cport1_id);
- request.intf2_id = intf2_id;
- request.cport2_id = cpu_to_le16(cport2_id);
-
- ret = gb_operation_sync(connection, GB_SVC_TYPE_CONN_DESTROY,
- &request, sizeof(request), NULL, 0);
- if (ret) {
- dev_err(&svc->dev, "failed to destroy connection (%u:%u %u:%u): %d\n",
- intf1_id, cport1_id, intf2_id, cport2_id, ret);
- }
-}
-
-/* Creates bi-directional routes between the devices */
-int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
- u8 intf2_id, u8 dev2_id)
-{
- struct gb_svc_route_create_request request;
-
- request.intf1_id = intf1_id;
- request.dev1_id = dev1_id;
- request.intf2_id = intf2_id;
- request.dev2_id = dev2_id;
-
- return gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_CREATE,
- &request, sizeof(request), NULL, 0);
-}
-
-/* Destroys bi-directional routes between the devices */
-void gb_svc_route_destroy(struct gb_svc *svc, u8 intf1_id, u8 intf2_id)
-{
- struct gb_svc_route_destroy_request request;
- int ret;
-
- request.intf1_id = intf1_id;
- request.intf2_id = intf2_id;
-
- ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_DESTROY,
- &request, sizeof(request), NULL, 0);
- if (ret) {
- dev_err(&svc->dev, "failed to destroy route (%u %u): %d\n",
- intf1_id, intf2_id, ret);
- }
-}
-
-int gb_svc_intf_set_power_mode(struct gb_svc *svc, u8 intf_id, u8 hs_series,
- u8 tx_mode, u8 tx_gear, u8 tx_nlanes,
- u8 tx_amplitude, u8 tx_hs_equalizer,
- u8 rx_mode, u8 rx_gear, u8 rx_nlanes,
- u8 flags, u32 quirks,
- struct gb_svc_l2_timer_cfg *local,
- struct gb_svc_l2_timer_cfg *remote)
-{
- struct gb_svc_intf_set_pwrm_request request;
- struct gb_svc_intf_set_pwrm_response response;
- int ret;
- u16 result_code;
-
- memset(&request, 0, sizeof(request));
-
- request.intf_id = intf_id;
- request.hs_series = hs_series;
- request.tx_mode = tx_mode;
- request.tx_gear = tx_gear;
- request.tx_nlanes = tx_nlanes;
- request.tx_amplitude = tx_amplitude;
- request.tx_hs_equalizer = tx_hs_equalizer;
- request.rx_mode = rx_mode;
- request.rx_gear = rx_gear;
- request.rx_nlanes = rx_nlanes;
- request.flags = flags;
- request.quirks = cpu_to_le32(quirks);
- if (local)
- request.local_l2timerdata = *local;
- if (remote)
- request.remote_l2timerdata = *remote;
-
- ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_SET_PWRM,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret < 0)
- return ret;
-
- result_code = response.result_code;
- if (result_code != GB_SVC_SETPWRM_PWR_LOCAL) {
- dev_err(&svc->dev, "set power mode = %d\n", result_code);
- return -EIO;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(gb_svc_intf_set_power_mode);
-
-int gb_svc_intf_set_power_mode_hibernate(struct gb_svc *svc, u8 intf_id)
-{
- struct gb_svc_intf_set_pwrm_request request;
- struct gb_svc_intf_set_pwrm_response response;
- int ret;
- u16 result_code;
-
- memset(&request, 0, sizeof(request));
-
- request.intf_id = intf_id;
- request.hs_series = GB_SVC_UNIPRO_HS_SERIES_A;
- request.tx_mode = GB_SVC_UNIPRO_HIBERNATE_MODE;
- request.rx_mode = GB_SVC_UNIPRO_HIBERNATE_MODE;
-
- ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_SET_PWRM,
- &request, sizeof(request),
- &response, sizeof(response));
- if (ret < 0) {
- dev_err(&svc->dev,
- "failed to send set power mode operation to interface %u: %d\n",
- intf_id, ret);
- return ret;
- }
-
- result_code = response.result_code;
- if (result_code != GB_SVC_SETPWRM_PWR_OK) {
- dev_err(&svc->dev,
- "failed to hibernate the link for interface %u: %u\n",
- intf_id, result_code);
- return -EIO;
- }
-
- return 0;
-}
-
-int gb_svc_ping(struct gb_svc *svc)
-{
- return gb_operation_sync_timeout(svc->connection, GB_SVC_TYPE_PING,
- NULL, 0, NULL, 0,
- GB_OPERATION_TIMEOUT_DEFAULT * 2);
-}
-
-static int gb_svc_version_request(struct gb_operation *op)
-{
- struct gb_connection *connection = op->connection;
- struct gb_svc *svc = gb_connection_get_data(connection);
- struct gb_svc_version_request *request;
- struct gb_svc_version_response *response;
-
- if (op->request->payload_size < sizeof(*request)) {
- dev_err(&svc->dev, "short version request (%zu < %zu)\n",
- op->request->payload_size,
- sizeof(*request));
- return -EINVAL;
- }
-
- request = op->request->payload;
-
- if (request->major > GB_SVC_VERSION_MAJOR) {
- dev_warn(&svc->dev, "unsupported major version (%u > %u)\n",
- request->major, GB_SVC_VERSION_MAJOR);
- return -ENOTSUPP;
- }
-
- svc->protocol_major = request->major;
- svc->protocol_minor = request->minor;
-
- if (!gb_operation_response_alloc(op, sizeof(*response), GFP_KERNEL))
- return -ENOMEM;
-
- response = op->response->payload;
- response->major = svc->protocol_major;
- response->minor = svc->protocol_minor;
-
- return 0;
-}
-
-static ssize_t pwr_debugfs_voltage_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset)
-{
- struct svc_debugfs_pwrmon_rail *pwrmon_rails =
- file_inode(file)->i_private;
- struct gb_svc *svc = pwrmon_rails->svc;
- int ret, desc;
- u32 value;
- char buff[16];
-
- ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
- GB_SVC_PWRMON_TYPE_VOL, &value);
- if (ret) {
- dev_err(&svc->dev,
- "failed to get voltage sample %u: %d\n",
- pwrmon_rails->id, ret);
- return ret;
- }
-
- desc = scnprintf(buff, sizeof(buff), "%u\n", value);
-
- return simple_read_from_buffer(buf, len, offset, buff, desc);
-}
-
-static ssize_t pwr_debugfs_current_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset)
-{
- struct svc_debugfs_pwrmon_rail *pwrmon_rails =
- file_inode(file)->i_private;
- struct gb_svc *svc = pwrmon_rails->svc;
- int ret, desc;
- u32 value;
- char buff[16];
-
- ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
- GB_SVC_PWRMON_TYPE_CURR, &value);
- if (ret) {
- dev_err(&svc->dev,
- "failed to get current sample %u: %d\n",
- pwrmon_rails->id, ret);
- return ret;
- }
-
- desc = scnprintf(buff, sizeof(buff), "%u\n", value);
-
- return simple_read_from_buffer(buf, len, offset, buff, desc);
-}
-
-static ssize_t pwr_debugfs_power_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset)
-{
- struct svc_debugfs_pwrmon_rail *pwrmon_rails =
- file_inode(file)->i_private;
- struct gb_svc *svc = pwrmon_rails->svc;
- int ret, desc;
- u32 value;
- char buff[16];
-
- ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
- GB_SVC_PWRMON_TYPE_PWR, &value);
- if (ret) {
- dev_err(&svc->dev, "failed to get power sample %u: %d\n",
- pwrmon_rails->id, ret);
- return ret;
- }
-
- desc = scnprintf(buff, sizeof(buff), "%u\n", value);
-
- return simple_read_from_buffer(buf, len, offset, buff, desc);
-}
-
-static const struct file_operations pwrmon_debugfs_voltage_fops = {
- .read = pwr_debugfs_voltage_read,
-};
-
-static const struct file_operations pwrmon_debugfs_current_fops = {
- .read = pwr_debugfs_current_read,
-};
-
-static const struct file_operations pwrmon_debugfs_power_fops = {
- .read = pwr_debugfs_power_read,
-};
-
-static void gb_svc_pwrmon_debugfs_init(struct gb_svc *svc)
-{
- int i;
- size_t bufsize;
- struct dentry *dent;
- struct gb_svc_pwrmon_rail_names_get_response *rail_names;
- u8 rail_count;
-
- dent = debugfs_create_dir("pwrmon", svc->debugfs_dentry);
- if (IS_ERR_OR_NULL(dent))
- return;
-
- if (gb_svc_pwrmon_rail_count_get(svc, &rail_count))
- goto err_pwrmon_debugfs;
-
- if (!rail_count || rail_count > GB_SVC_PWRMON_MAX_RAIL_COUNT)
- goto err_pwrmon_debugfs;
-
- bufsize = sizeof(*rail_names) +
- GB_SVC_PWRMON_RAIL_NAME_BUFSIZE * rail_count;
-
- rail_names = kzalloc(bufsize, GFP_KERNEL);
- if (!rail_names)
- goto err_pwrmon_debugfs;
-
- svc->pwrmon_rails = kcalloc(rail_count, sizeof(*svc->pwrmon_rails),
- GFP_KERNEL);
- if (!svc->pwrmon_rails)
- goto err_pwrmon_debugfs_free;
-
- if (gb_svc_pwrmon_rail_names_get(svc, rail_names, bufsize))
- goto err_pwrmon_debugfs_free;
-
- for (i = 0; i < rail_count; i++) {
- struct dentry *dir;
- struct svc_debugfs_pwrmon_rail *rail = &svc->pwrmon_rails[i];
- char fname[GB_SVC_PWRMON_RAIL_NAME_BUFSIZE];
-
- snprintf(fname, sizeof(fname), "%s",
- (char *)&rail_names->name[i]);
-
- rail->id = i;
- rail->svc = svc;
-
- dir = debugfs_create_dir(fname, dent);
- debugfs_create_file("voltage_now", 0444, dir, rail,
- &pwrmon_debugfs_voltage_fops);
- debugfs_create_file("current_now", 0444, dir, rail,
- &pwrmon_debugfs_current_fops);
- debugfs_create_file("power_now", 0444, dir, rail,
- &pwrmon_debugfs_power_fops);
- }
-
- kfree(rail_names);
- return;
-
-err_pwrmon_debugfs_free:
- kfree(rail_names);
- kfree(svc->pwrmon_rails);
- svc->pwrmon_rails = NULL;
-
-err_pwrmon_debugfs:
- debugfs_remove(dent);
-}
-
-static void gb_svc_debugfs_init(struct gb_svc *svc)
-{
- svc->debugfs_dentry = debugfs_create_dir(dev_name(&svc->dev),
- gb_debugfs_get());
- gb_svc_pwrmon_debugfs_init(svc);
-}
-
-static void gb_svc_debugfs_exit(struct gb_svc *svc)
-{
- debugfs_remove_recursive(svc->debugfs_dentry);
- kfree(svc->pwrmon_rails);
- svc->pwrmon_rails = NULL;
-}
-
-static int gb_svc_hello(struct gb_operation *op)
-{
- struct gb_connection *connection = op->connection;
- struct gb_svc *svc = gb_connection_get_data(connection);
- struct gb_svc_hello_request *hello_request;
- int ret;
-
- if (op->request->payload_size < sizeof(*hello_request)) {
- dev_warn(&svc->dev, "short hello request (%zu < %zu)\n",
- op->request->payload_size,
- sizeof(*hello_request));
- return -EINVAL;
- }
-
- hello_request = op->request->payload;
- svc->endo_id = le16_to_cpu(hello_request->endo_id);
- svc->ap_intf_id = hello_request->interface_id;
-
- ret = device_add(&svc->dev);
- if (ret) {
- dev_err(&svc->dev, "failed to register svc device: %d\n", ret);
- return ret;
- }
-
- ret = gb_svc_watchdog_create(svc);
- if (ret) {
- dev_err(&svc->dev, "failed to create watchdog: %d\n", ret);
- goto err_unregister_device;
- }
-
- gb_svc_debugfs_init(svc);
-
- return gb_svc_queue_deferred_request(op);
-
-err_unregister_device:
- gb_svc_watchdog_destroy(svc);
- device_del(&svc->dev);
- return ret;
-}
-
-static struct gb_interface *gb_svc_interface_lookup(struct gb_svc *svc,
- u8 intf_id)
-{
- struct gb_host_device *hd = svc->hd;
- struct gb_module *module;
- size_t num_interfaces;
- u8 module_id;
-
- list_for_each_entry(module, &hd->modules, hd_node) {
- module_id = module->module_id;
- num_interfaces = module->num_interfaces;
-
- if (intf_id >= module_id &&
- intf_id < module_id + num_interfaces) {
- return module->interfaces[intf_id - module_id];
- }
- }
-
- return NULL;
-}
-
-static struct gb_module *gb_svc_module_lookup(struct gb_svc *svc, u8 module_id)
-{
- struct gb_host_device *hd = svc->hd;
- struct gb_module *module;
-
- list_for_each_entry(module, &hd->modules, hd_node) {
- if (module->module_id == module_id)
- return module;
- }
-
- return NULL;
-}
-
-static void gb_svc_process_hello_deferred(struct gb_operation *operation)
-{
- struct gb_connection *connection = operation->connection;
- struct gb_svc *svc = gb_connection_get_data(connection);
- int ret;
-
- /*
- * XXX This is a hack/work-around to reconfigure the APBridgeA-Switch
- * link to PWM G2, 1 Lane, Slow Auto, so that it has sufficient
- * bandwidth for 3 audio streams plus boot-over-UniPro of a hot-plugged
- * module.
- *
- * The code should be removed once SW-2217, Heuristic for UniPro
- * Power Mode Changes is resolved.
- */
- ret = gb_svc_intf_set_power_mode(svc, svc->ap_intf_id,
- GB_SVC_UNIPRO_HS_SERIES_A,
- GB_SVC_UNIPRO_SLOW_AUTO_MODE,
- 2, 1,
- GB_SVC_SMALL_AMPLITUDE,
- GB_SVC_NO_DE_EMPHASIS,
- GB_SVC_UNIPRO_SLOW_AUTO_MODE,
- 2, 1,
- 0, 0,
- NULL, NULL);
-
- if (ret)
- dev_warn(&svc->dev,
- "power mode change failed on AP to switch link: %d\n",
- ret);
-}
-
-static void gb_svc_process_module_inserted(struct gb_operation *operation)
-{
- struct gb_svc_module_inserted_request *request;
- struct gb_connection *connection = operation->connection;
- struct gb_svc *svc = gb_connection_get_data(connection);
- struct gb_host_device *hd = svc->hd;
- struct gb_module *module;
- size_t num_interfaces;
- u8 module_id;
- u16 flags;
- int ret;
-
- /* The request message size has already been verified. */
- request = operation->request->payload;
- module_id = request->primary_intf_id;
- num_interfaces = request->intf_count;
- flags = le16_to_cpu(request->flags);
-
- dev_dbg(&svc->dev, "%s - id = %u, num_interfaces = %zu, flags = 0x%04x\n",
- __func__, module_id, num_interfaces, flags);
-
- if (flags & GB_SVC_MODULE_INSERTED_FLAG_NO_PRIMARY) {
- dev_warn(&svc->dev, "no primary interface detected on module %u\n",
- module_id);
- }
-
- module = gb_svc_module_lookup(svc, module_id);
- if (module) {
- dev_warn(&svc->dev, "unexpected module-inserted event %u\n",
- module_id);
- return;
- }
-
- module = gb_module_create(hd, module_id, num_interfaces);
- if (!module) {
- dev_err(&svc->dev, "failed to create module\n");
- return;
- }
-
- ret = gb_module_add(module);
- if (ret) {
- gb_module_put(module);
- return;
- }
-
- list_add(&module->hd_node, &hd->modules);
-}
-
-static void gb_svc_process_module_removed(struct gb_operation *operation)
-{
- struct gb_svc_module_removed_request *request;
- struct gb_connection *connection = operation->connection;
- struct gb_svc *svc = gb_connection_get_data(connection);
- struct gb_module *module;
- u8 module_id;
-
- /* The request message size has already been verified. */
- request = operation->request->payload;
- module_id = request->primary_intf_id;
-
- dev_dbg(&svc->dev, "%s - id = %u\n", __func__, module_id);
-
- module = gb_svc_module_lookup(svc, module_id);
- if (!module) {
- dev_warn(&svc->dev, "unexpected module-removed event %u\n",
- module_id);
- return;
- }
-
- module->disconnected = true;
-
- gb_module_del(module);
- list_del(&module->hd_node);
- gb_module_put(module);
-}
-
-static void gb_svc_process_intf_oops(struct gb_operation *operation)
-{
- struct gb_svc_intf_oops_request *request;
- struct gb_connection *connection = operation->connection;
- struct gb_svc *svc = gb_connection_get_data(connection);
- struct gb_interface *intf;
- u8 intf_id;
- u8 reason;
-
- /* The request message size has already been verified. */
- request = operation->request->payload;
- intf_id = request->intf_id;
- reason = request->reason;
-
- intf = gb_svc_interface_lookup(svc, intf_id);
- if (!intf) {
- dev_warn(&svc->dev, "unexpected interface-oops event %u\n",
- intf_id);
- return;
- }
-
- dev_info(&svc->dev, "Deactivating interface %u, interface oops reason = %u\n",
- intf_id, reason);
-
- mutex_lock(&intf->mutex);
- intf->disconnected = true;
- gb_interface_disable(intf);
- gb_interface_deactivate(intf);
- mutex_unlock(&intf->mutex);
-}
-
-static void gb_svc_process_intf_mailbox_event(struct gb_operation *operation)
-{
- struct gb_svc_intf_mailbox_event_request *request;
- struct gb_connection *connection = operation->connection;
- struct gb_svc *svc = gb_connection_get_data(connection);
- struct gb_interface *intf;
- u8 intf_id;
- u16 result_code;
- u32 mailbox;
-
- /* The request message size has already been verified. */
- request = operation->request->payload;
- intf_id = request->intf_id;
- result_code = le16_to_cpu(request->result_code);
- mailbox = le32_to_cpu(request->mailbox);
-
- dev_dbg(&svc->dev, "%s - id = %u, result = 0x%04x, mailbox = 0x%08x\n",
- __func__, intf_id, result_code, mailbox);
-
- intf = gb_svc_interface_lookup(svc, intf_id);
- if (!intf) {
- dev_warn(&svc->dev, "unexpected mailbox event %u\n", intf_id);
- return;
- }
-
- gb_interface_mailbox_event(intf, result_code, mailbox);
-}
-
-static void gb_svc_process_deferred_request(struct work_struct *work)
-{
- struct gb_svc_deferred_request *dr;
- struct gb_operation *operation;
- struct gb_svc *svc;
- u8 type;
-
- dr = container_of(work, struct gb_svc_deferred_request, work);
- operation = dr->operation;
- svc = gb_connection_get_data(operation->connection);
- type = operation->request->header->type;
-
- switch (type) {
- case GB_SVC_TYPE_SVC_HELLO:
- gb_svc_process_hello_deferred(operation);
- break;
- case GB_SVC_TYPE_MODULE_INSERTED:
- gb_svc_process_module_inserted(operation);
- break;
- case GB_SVC_TYPE_MODULE_REMOVED:
- gb_svc_process_module_removed(operation);
- break;
- case GB_SVC_TYPE_INTF_MAILBOX_EVENT:
- gb_svc_process_intf_mailbox_event(operation);
- break;
- case GB_SVC_TYPE_INTF_OOPS:
- gb_svc_process_intf_oops(operation);
- break;
- default:
- dev_err(&svc->dev, "bad deferred request type: 0x%02x\n", type);
- }
-
- gb_operation_put(operation);
- kfree(dr);
-}
-
-static int gb_svc_queue_deferred_request(struct gb_operation *operation)
-{
- struct gb_svc *svc = gb_connection_get_data(operation->connection);
- struct gb_svc_deferred_request *dr;
-
- dr = kmalloc(sizeof(*dr), GFP_KERNEL);
- if (!dr)
- return -ENOMEM;
-
- gb_operation_get(operation);
-
- dr->operation = operation;
- INIT_WORK(&dr->work, gb_svc_process_deferred_request);
-
- queue_work(svc->wq, &dr->work);
-
- return 0;
-}
-
-static int gb_svc_intf_reset_recv(struct gb_operation *op)
-{
- struct gb_svc *svc = gb_connection_get_data(op->connection);
- struct gb_message *request = op->request;
- struct gb_svc_intf_reset_request *reset;
-
- if (request->payload_size < sizeof(*reset)) {
- dev_warn(&svc->dev, "short reset request received (%zu < %zu)\n",
- request->payload_size, sizeof(*reset));
- return -EINVAL;
- }
- reset = request->payload;
-
- /* FIXME Reset the interface here */
-
- return 0;
-}
-
-static int gb_svc_module_inserted_recv(struct gb_operation *op)
-{
- struct gb_svc *svc = gb_connection_get_data(op->connection);
- struct gb_svc_module_inserted_request *request;
-
- if (op->request->payload_size < sizeof(*request)) {
- dev_warn(&svc->dev, "short module-inserted request received (%zu < %zu)\n",
- op->request->payload_size, sizeof(*request));
- return -EINVAL;
- }
-
- request = op->request->payload;
-
- dev_dbg(&svc->dev, "%s - id = %u\n", __func__,
- request->primary_intf_id);
-
- return gb_svc_queue_deferred_request(op);
-}
-
-static int gb_svc_module_removed_recv(struct gb_operation *op)
-{
- struct gb_svc *svc = gb_connection_get_data(op->connection);
- struct gb_svc_module_removed_request *request;
-
- if (op->request->payload_size < sizeof(*request)) {
- dev_warn(&svc->dev, "short module-removed request received (%zu < %zu)\n",
- op->request->payload_size, sizeof(*request));
- return -EINVAL;
- }
-
- request = op->request->payload;
-
- dev_dbg(&svc->dev, "%s - id = %u\n", __func__,
- request->primary_intf_id);
-
- return gb_svc_queue_deferred_request(op);
-}
-
-static int gb_svc_intf_oops_recv(struct gb_operation *op)
-{
- struct gb_svc *svc = gb_connection_get_data(op->connection);
- struct gb_svc_intf_oops_request *request;
-
- if (op->request->payload_size < sizeof(*request)) {
- dev_warn(&svc->dev, "short intf-oops request received (%zu < %zu)\n",
- op->request->payload_size, sizeof(*request));
- return -EINVAL;
- }
-
- return gb_svc_queue_deferred_request(op);
-}
-
-static int gb_svc_intf_mailbox_event_recv(struct gb_operation *op)
-{
- struct gb_svc *svc = gb_connection_get_data(op->connection);
- struct gb_svc_intf_mailbox_event_request *request;
-
- if (op->request->payload_size < sizeof(*request)) {
- dev_warn(&svc->dev, "short mailbox request received (%zu < %zu)\n",
- op->request->payload_size, sizeof(*request));
- return -EINVAL;
- }
-
- request = op->request->payload;
-
- dev_dbg(&svc->dev, "%s - id = %u\n", __func__, request->intf_id);
-
- return gb_svc_queue_deferred_request(op);
-}
-
-static int gb_svc_request_handler(struct gb_operation *op)
-{
- struct gb_connection *connection = op->connection;
- struct gb_svc *svc = gb_connection_get_data(connection);
- u8 type = op->type;
- int ret = 0;
-
- /*
- * SVC requests need to follow a specific order (at least initially) and
- * below code takes care of enforcing that. The expected order is:
- * - PROTOCOL_VERSION
- * - SVC_HELLO
- * - Any other request, but the earlier two.
- *
- * Incoming requests are guaranteed to be serialized and so we don't
- * need to protect 'state' for any races.
- */
- switch (type) {
- case GB_SVC_TYPE_PROTOCOL_VERSION:
- if (svc->state != GB_SVC_STATE_RESET)
- ret = -EINVAL;
- break;
- case GB_SVC_TYPE_SVC_HELLO:
- if (svc->state != GB_SVC_STATE_PROTOCOL_VERSION)
- ret = -EINVAL;
- break;
- default:
- if (svc->state != GB_SVC_STATE_SVC_HELLO)
- ret = -EINVAL;
- break;
- }
-
- if (ret) {
- dev_warn(&svc->dev, "unexpected request 0x%02x received (state %u)\n",
- type, svc->state);
- return ret;
- }
-
- switch (type) {
- case GB_SVC_TYPE_PROTOCOL_VERSION:
- ret = gb_svc_version_request(op);
- if (!ret)
- svc->state = GB_SVC_STATE_PROTOCOL_VERSION;
- return ret;
- case GB_SVC_TYPE_SVC_HELLO:
- ret = gb_svc_hello(op);
- if (!ret)
- svc->state = GB_SVC_STATE_SVC_HELLO;
- return ret;
- case GB_SVC_TYPE_INTF_RESET:
- return gb_svc_intf_reset_recv(op);
- case GB_SVC_TYPE_MODULE_INSERTED:
- return gb_svc_module_inserted_recv(op);
- case GB_SVC_TYPE_MODULE_REMOVED:
- return gb_svc_module_removed_recv(op);
- case GB_SVC_TYPE_INTF_MAILBOX_EVENT:
- return gb_svc_intf_mailbox_event_recv(op);
- case GB_SVC_TYPE_INTF_OOPS:
- return gb_svc_intf_oops_recv(op);
- default:
- dev_warn(&svc->dev, "unsupported request 0x%02x\n", type);
- return -EINVAL;
- }
-}
-
-static void gb_svc_release(struct device *dev)
-{
- struct gb_svc *svc = to_gb_svc(dev);
-
- if (svc->connection)
- gb_connection_destroy(svc->connection);
- ida_destroy(&svc->device_id_map);
- destroy_workqueue(svc->wq);
- kfree(svc);
-}
-
-struct device_type greybus_svc_type = {
- .name = "greybus_svc",
- .release = gb_svc_release,
-};
-
-struct gb_svc *gb_svc_create(struct gb_host_device *hd)
-{
- struct gb_svc *svc;
-
- svc = kzalloc(sizeof(*svc), GFP_KERNEL);
- if (!svc)
- return NULL;
-
- svc->wq = alloc_workqueue("%s:svc", WQ_UNBOUND, 1, dev_name(&hd->dev));
- if (!svc->wq) {
- kfree(svc);
- return NULL;
- }
-
- svc->dev.parent = &hd->dev;
- svc->dev.bus = &greybus_bus_type;
- svc->dev.type = &greybus_svc_type;
- svc->dev.groups = svc_groups;
- svc->dev.dma_mask = svc->dev.parent->dma_mask;
- device_initialize(&svc->dev);
-
- dev_set_name(&svc->dev, "%d-svc", hd->bus_id);
-
- ida_init(&svc->device_id_map);
- svc->state = GB_SVC_STATE_RESET;
- svc->hd = hd;
-
- svc->connection = gb_connection_create_static(hd, GB_SVC_CPORT_ID,
- gb_svc_request_handler);
- if (IS_ERR(svc->connection)) {
- dev_err(&svc->dev, "failed to create connection: %ld\n",
- PTR_ERR(svc->connection));
- goto err_put_device;
- }
-
- gb_connection_set_data(svc->connection, svc);
-
- return svc;
-
-err_put_device:
- put_device(&svc->dev);
- return NULL;
-}
-
-int gb_svc_add(struct gb_svc *svc)
-{
- int ret;
-
- /*
- * The SVC protocol is currently driven by the SVC, so the SVC device
- * is added from the connection request handler when enough
- * information has been received.
- */
- ret = gb_connection_enable(svc->connection);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void gb_svc_remove_modules(struct gb_svc *svc)
-{
- struct gb_host_device *hd = svc->hd;
- struct gb_module *module, *tmp;
-
- list_for_each_entry_safe(module, tmp, &hd->modules, hd_node) {
- gb_module_del(module);
- list_del(&module->hd_node);
- gb_module_put(module);
- }
-}
-
-void gb_svc_del(struct gb_svc *svc)
-{
- gb_connection_disable_rx(svc->connection);
-
- /*
- * The SVC device may have been registered from the request handler.
- */
- if (device_is_registered(&svc->dev)) {
- gb_svc_debugfs_exit(svc);
- gb_svc_watchdog_destroy(svc);
- device_del(&svc->dev);
- }
-
- flush_workqueue(svc->wq);
-
- gb_svc_remove_modules(svc);
-
- gb_connection_disable(svc->connection);
-}
-
-void gb_svc_put(struct gb_svc *svc)
-{
- put_device(&svc->dev);
-}
diff --git a/drivers/staging/greybus/svc.h b/drivers/staging/greybus/svc.h
deleted file mode 100644
index ad01783bac9c..000000000000
--- a/drivers/staging/greybus/svc.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Greybus SVC code
- *
- * Copyright 2015 Google Inc.
- * Copyright 2015 Linaro Ltd.
- */
-
-#ifndef __SVC_H
-#define __SVC_H
-
-#define GB_SVC_CPORT_FLAG_E2EFC BIT(0)
-#define GB_SVC_CPORT_FLAG_CSD_N BIT(1)
-#define GB_SVC_CPORT_FLAG_CSV_N BIT(2)
-
-enum gb_svc_state {
- GB_SVC_STATE_RESET,
- GB_SVC_STATE_PROTOCOL_VERSION,
- GB_SVC_STATE_SVC_HELLO,
-};
-
-enum gb_svc_watchdog_bite {
- GB_SVC_WATCHDOG_BITE_RESET_UNIPRO = 0,
- GB_SVC_WATCHDOG_BITE_PANIC_KERNEL,
-};
-
-struct gb_svc_watchdog;
-
-struct svc_debugfs_pwrmon_rail {
- u8 id;
- struct gb_svc *svc;
-};
-
-struct gb_svc {
- struct device dev;
-
- struct gb_host_device *hd;
- struct gb_connection *connection;
- enum gb_svc_state state;
- struct ida device_id_map;
- struct workqueue_struct *wq;
-
- u16 endo_id;
- u8 ap_intf_id;
-
- u8 protocol_major;
- u8 protocol_minor;
-
- struct gb_svc_watchdog *watchdog;
- enum gb_svc_watchdog_bite action;
-
- struct dentry *debugfs_dentry;
- struct svc_debugfs_pwrmon_rail *pwrmon_rails;
-};
-#define to_gb_svc(d) container_of(d, struct gb_svc, dev)
-
-struct gb_svc *gb_svc_create(struct gb_host_device *hd);
-int gb_svc_add(struct gb_svc *svc);
-void gb_svc_del(struct gb_svc *svc);
-void gb_svc_put(struct gb_svc *svc);
-
-int gb_svc_pwrmon_intf_sample_get(struct gb_svc *svc, u8 intf_id,
- u8 measurement_type, u32 *value);
-int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id);
-int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
- u8 intf2_id, u8 dev2_id);
-void gb_svc_route_destroy(struct gb_svc *svc, u8 intf1_id, u8 intf2_id);
-int gb_svc_connection_create(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
- u8 intf2_id, u16 cport2_id, u8 cport_flags);
-void gb_svc_connection_destroy(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
- u8 intf2_id, u16 cport2_id);
-int gb_svc_intf_eject(struct gb_svc *svc, u8 intf_id);
-int gb_svc_intf_vsys_set(struct gb_svc *svc, u8 intf_id, bool enable);
-int gb_svc_intf_refclk_set(struct gb_svc *svc, u8 intf_id, bool enable);
-int gb_svc_intf_unipro_set(struct gb_svc *svc, u8 intf_id, bool enable);
-int gb_svc_intf_activate(struct gb_svc *svc, u8 intf_id, u8 *intf_type);
-int gb_svc_intf_resume(struct gb_svc *svc, u8 intf_id);
-
-int gb_svc_dme_peer_get(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
- u32 *value);
-int gb_svc_dme_peer_set(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
- u32 value);
-int gb_svc_intf_set_power_mode(struct gb_svc *svc, u8 intf_id, u8 hs_series,
- u8 tx_mode, u8 tx_gear, u8 tx_nlanes,
- u8 tx_amplitude, u8 tx_hs_equalizer,
- u8 rx_mode, u8 rx_gear, u8 rx_nlanes,
- u8 flags, u32 quirks,
- struct gb_svc_l2_timer_cfg *local,
- struct gb_svc_l2_timer_cfg *remote);
-int gb_svc_intf_set_power_mode_hibernate(struct gb_svc *svc, u8 intf_id);
-int gb_svc_ping(struct gb_svc *svc);
-int gb_svc_watchdog_create(struct gb_svc *svc);
-void gb_svc_watchdog_destroy(struct gb_svc *svc);
-bool gb_svc_watchdog_enabled(struct gb_svc *svc);
-int gb_svc_watchdog_enable(struct gb_svc *svc);
-int gb_svc_watchdog_disable(struct gb_svc *svc);
-
-int gb_svc_protocol_init(void);
-void gb_svc_protocol_exit(void);
-
-#endif /* __SVC_H */
diff --git a/drivers/staging/greybus/svc_watchdog.c b/drivers/staging/greybus/svc_watchdog.c
deleted file mode 100644
index 7868ad8211c5..000000000000
--- a/drivers/staging/greybus/svc_watchdog.c
+++ /dev/null
@@ -1,197 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * SVC Greybus "watchdog" driver.
- *
- * Copyright 2016 Google Inc.
- */
-
-#include <linux/delay.h>
-#include <linux/suspend.h>
-#include <linux/workqueue.h>
-#include "greybus.h"
-
-#define SVC_WATCHDOG_PERIOD (2 * HZ)
-
-struct gb_svc_watchdog {
- struct delayed_work work;
- struct gb_svc *svc;
- bool enabled;
- struct notifier_block pm_notifier;
-};
-
-static struct delayed_work reset_work;
-
-static int svc_watchdog_pm_notifier(struct notifier_block *notifier,
- unsigned long pm_event, void *unused)
-{
- struct gb_svc_watchdog *watchdog =
- container_of(notifier, struct gb_svc_watchdog, pm_notifier);
-
- switch (pm_event) {
- case PM_SUSPEND_PREPARE:
- gb_svc_watchdog_disable(watchdog->svc);
- break;
- case PM_POST_SUSPEND:
- gb_svc_watchdog_enable(watchdog->svc);
- break;
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-static void greybus_reset(struct work_struct *work)
-{
- static char const start_path[] = "/system/bin/start";
- static char *envp[] = {
- "HOME=/",
- "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin",
- NULL,
- };
- static char *argv[] = {
- (char *)start_path,
- "unipro_reset",
- NULL,
- };
-
- pr_err("svc_watchdog: calling \"%s %s\" to reset greybus network!\n",
- argv[0], argv[1]);
- call_usermodehelper(start_path, argv, envp, UMH_WAIT_EXEC);
-}
-
-static void do_work(struct work_struct *work)
-{
- struct gb_svc_watchdog *watchdog;
- struct gb_svc *svc;
- int retval;
-
- watchdog = container_of(work, struct gb_svc_watchdog, work.work);
- svc = watchdog->svc;
-
- dev_dbg(&svc->dev, "%s: ping.\n", __func__);
- retval = gb_svc_ping(svc);
- if (retval) {
- /*
- * Something went really wrong, let's warn userspace and then
- * pull the plug and reset the whole greybus network.
- * We need to do this outside of this workqueue as we will be
- * tearing down the svc device itself. So queue up
- * yet-another-callback to do that.
- */
- dev_err(&svc->dev,
- "SVC ping has returned %d, something is wrong!!!\n",
- retval);
-
- if (svc->action == GB_SVC_WATCHDOG_BITE_PANIC_KERNEL) {
- panic("SVC is not responding\n");
- } else if (svc->action == GB_SVC_WATCHDOG_BITE_RESET_UNIPRO) {
- dev_err(&svc->dev, "Resetting the greybus network, watch out!!!\n");
-
- INIT_DELAYED_WORK(&reset_work, greybus_reset);
- schedule_delayed_work(&reset_work, HZ / 2);
-
- /*
- * Disable ourselves, we don't want to trip again unless
- * userspace wants us to.
- */
- watchdog->enabled = false;
- }
- }
-
- /* resubmit our work to happen again, if we are still "alive" */
- if (watchdog->enabled)
- schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD);
-}
-
-int gb_svc_watchdog_create(struct gb_svc *svc)
-{
- struct gb_svc_watchdog *watchdog;
- int retval;
-
- if (svc->watchdog)
- return 0;
-
- watchdog = kmalloc(sizeof(*watchdog), GFP_KERNEL);
- if (!watchdog)
- return -ENOMEM;
-
- watchdog->enabled = false;
- watchdog->svc = svc;
- INIT_DELAYED_WORK(&watchdog->work, do_work);
- svc->watchdog = watchdog;
-
- watchdog->pm_notifier.notifier_call = svc_watchdog_pm_notifier;
- retval = register_pm_notifier(&watchdog->pm_notifier);
- if (retval) {
- dev_err(&svc->dev, "error registering pm notifier(%d)\n",
- retval);
- goto svc_watchdog_create_err;
- }
-
- retval = gb_svc_watchdog_enable(svc);
- if (retval) {
- dev_err(&svc->dev, "error enabling watchdog (%d)\n", retval);
- unregister_pm_notifier(&watchdog->pm_notifier);
- goto svc_watchdog_create_err;
- }
- return retval;
-
-svc_watchdog_create_err:
- svc->watchdog = NULL;
- kfree(watchdog);
-
- return retval;
-}
-
-void gb_svc_watchdog_destroy(struct gb_svc *svc)
-{
- struct gb_svc_watchdog *watchdog = svc->watchdog;
-
- if (!watchdog)
- return;
-
- unregister_pm_notifier(&watchdog->pm_notifier);
- gb_svc_watchdog_disable(svc);
- svc->watchdog = NULL;
- kfree(watchdog);
-}
-
-bool gb_svc_watchdog_enabled(struct gb_svc *svc)
-{
- if (!svc || !svc->watchdog)
- return false;
- return svc->watchdog->enabled;
-}
-
-int gb_svc_watchdog_enable(struct gb_svc *svc)
-{
- struct gb_svc_watchdog *watchdog;
-
- if (!svc->watchdog)
- return -ENODEV;
-
- watchdog = svc->watchdog;
- if (watchdog->enabled)
- return 0;
-
- watchdog->enabled = true;
- schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD);
- return 0;
-}
-
-int gb_svc_watchdog_disable(struct gb_svc *svc)
-{
- struct gb_svc_watchdog *watchdog;
-
- if (!svc->watchdog)
- return -ENODEV;
-
- watchdog = svc->watchdog;
- if (!watchdog->enabled)
- return 0;
-
- watchdog->enabled = false;
- cancel_delayed_work_sync(&watchdog->work);
- return 0;
-}
diff --git a/drivers/staging/greybus/tools/loopback_test.c b/drivers/staging/greybus/tools/loopback_test.c
index cebc1d90a180..ba6f905f26fa 100644
--- a/drivers/staging/greybus/tools/loopback_test.c
+++ b/drivers/staging/greybus/tools/loopback_test.c
@@ -4,8 +4,6 @@
*
* Copyright 2015 Google Inc.
* Copyright 2015 Linaro Ltd.
- *
- * Provided under the three clause BSD license found in the LICENSE file.
*/
#include <errno.h>
#include <fcntl.h>
diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c
index b3bffe91ae99..55c51143bb09 100644
--- a/drivers/staging/greybus/uart.c
+++ b/drivers/staging/greybus/uart.c
@@ -28,8 +28,8 @@
#include <linux/kfifo.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "gbphy.h"
#define GB_NUM_MINORS 16 /* 16 is more than enough */
diff --git a/drivers/staging/greybus/usb.c b/drivers/staging/greybus/usb.c
index 1c246c73a085..8e9d9d59a357 100644
--- a/drivers/staging/greybus/usb.c
+++ b/drivers/staging/greybus/usb.c
@@ -10,8 +10,8 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <linux/greybus.h>
-#include "greybus.h"
#include "gbphy.h"
/* Greybus USB request types */
diff --git a/drivers/staging/greybus/vibrator.c b/drivers/staging/greybus/vibrator.c
index 3e5dedeacd5c..0e2b188e5ca3 100644
--- a/drivers/staging/greybus/vibrator.c
+++ b/drivers/staging/greybus/vibrator.c
@@ -13,8 +13,7 @@
#include <linux/kdev_t.h>
#include <linux/idr.h>
#include <linux/pm_runtime.h>
-
-#include "greybus.h"
+#include <linux/greybus.h>
struct gb_vibrator_device {
struct gb_connection *connection;
diff --git a/drivers/staging/iio/accel/adis16240.c b/drivers/staging/iio/accel/adis16240.c
index 62f4b3b1b457..82099db4bf0c 100644
--- a/drivers/staging/iio/accel/adis16240.c
+++ b/drivers/staging/iio/accel/adis16240.c
@@ -309,15 +309,12 @@ static int adis16240_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct adis *st = iio_priv(indio_dev);
- int bits = 10;
- s16 val16;
u8 addr;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
- val16 = val & ((1 << bits) - 1);
addr = adis16240_addresses[chan->scan_index][0];
- return adis_write_reg_16(st, addr, val16);
+ return adis_write_reg_16(st, addr, val & GENMASK(9, 0));
}
return -EINVAL;
}
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index b6d12fe7c12a..e6b660489165 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -25,8 +25,6 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
-#include "ad7192.h"
-
/* Registers */
#define AD7192_REG_COMM 0 /* Communications Register (WO, 8-bit) */
#define AD7192_REG_STAT 0 /* Status Register (RO, 8-bit) */
@@ -145,6 +143,10 @@
#define AD7192_EXT_FREQ_MHZ_MAX 5120000
#define AD7192_INT_FREQ_MHZ 4915200
+#define AD7192_NO_SYNC_FILTER 1
+#define AD7192_SYNC3_FILTER 3
+#define AD7192_SYNC4_FILTER 4
+
/* NOTE:
* The AD7190/2/5 features a dual use data out ready DOUT/RDY output.
* In order to avoid contentions on the SPI bus, it's therefore necessary
@@ -252,7 +254,7 @@ static int ad7192_of_clock_select(struct ad7192_state *st)
static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
{
struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi);
- bool rej60_en, sinc3_en, refin2_en, chop_en;
+ bool rej60_en, refin2_en;
bool buf_en, bipolar, burnout_curr_en;
unsigned long long scale_uv;
int i, ret, id;
@@ -284,24 +286,12 @@ static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
if (rej60_en)
st->mode |= AD7192_MODE_REJ60;
- sinc3_en = of_property_read_bool(np, "adi,sinc3-filter-enable");
- if (sinc3_en)
- st->mode |= AD7192_MODE_SINC3;
-
refin2_en = of_property_read_bool(np, "adi,refin2-pins-enable");
if (refin2_en && st->devid != ID_AD7195)
st->conf |= AD7192_CONF_REFSEL;
- chop_en = of_property_read_bool(np, "adi,chop-enable");
- if (chop_en) {
- st->conf |= AD7192_CONF_CHOP;
- if (sinc3_en)
- st->f_order = 3; /* SINC 3rd order */
- else
- st->f_order = 4; /* SINC 4th order */
- } else {
- st->f_order = 1;
- }
+ st->conf &= ~AD7192_CONF_CHOP;
+ st->f_order = AD7192_NO_SYNC_FILTER;
buf_en = of_property_read_bool(np, "adi,buffer-enable");
if (buf_en)
@@ -313,7 +303,7 @@ static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
burnout_curr_en = of_property_read_bool(np,
"adi,burnout-currents-enable");
- if (burnout_curr_en && buf_en && !chop_en) {
+ if (burnout_curr_en && buf_en) {
st->conf |= AD7192_CONF_BURN;
} else if (burnout_curr_en) {
dev_warn(&st->sd.spi->dev,
@@ -411,6 +401,49 @@ static ssize_t ad7192_set(struct device *dev,
return ret ? ret : len;
}
+static void ad7192_get_available_filter_freq(struct ad7192_state *st,
+ int *freq)
+{
+ unsigned int fadc;
+
+ /* Formulas for filter at page 25 of the datasheet */
+ fadc = DIV_ROUND_CLOSEST(st->fclk,
+ AD7192_SYNC4_FILTER * AD7192_MODE_RATE(st->mode));
+ freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
+
+ fadc = DIV_ROUND_CLOSEST(st->fclk,
+ AD7192_SYNC3_FILTER * AD7192_MODE_RATE(st->mode));
+ freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
+
+ fadc = DIV_ROUND_CLOSEST(st->fclk, AD7192_MODE_RATE(st->mode));
+ freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
+ freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
+}
+
+static ssize_t ad7192_show_filter_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad7192_state *st = iio_priv(indio_dev);
+ unsigned int freq_avail[4], i;
+ size_t len = 0;
+
+ ad7192_get_available_filter_freq(st, freq_avail);
+
+ for (i = 0; i < ARRAY_SIZE(freq_avail); i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len,
+ "%d.%d ", freq_avail[i] / 1000,
+ freq_avail[i] % 1000);
+
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(filter_low_pass_3db_frequency_available,
+ 0444, ad7192_show_filter_avail, NULL, 0);
+
static IIO_DEVICE_ATTR(bridge_switch_en, 0644,
ad7192_show_bridge_switch, ad7192_set,
AD7192_REG_GPOCON);
@@ -420,6 +453,7 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
AD7192_REG_MODE);
static struct attribute *ad7192_attributes[] = {
+ &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
&iio_dev_attr_ac_excitation_en.dev_attr.attr,
NULL
@@ -430,6 +464,7 @@ static const struct attribute_group ad7192_attribute_group = {
};
static struct attribute *ad7195_attributes[] = {
+ &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
NULL
};
@@ -443,6 +478,75 @@ static unsigned int ad7192_get_temp_scale(bool unipolar)
return unipolar ? 2815 * 2 : 2815;
}
+static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
+ int val, int val2)
+{
+ int freq_avail[4], i, ret, freq;
+ unsigned int diff_new, diff_old;
+ int idx = 0;
+
+ diff_old = U32_MAX;
+ freq = val * 1000 + val2;
+
+ ad7192_get_available_filter_freq(st, freq_avail);
+
+ for (i = 0; i < ARRAY_SIZE(freq_avail); i++) {
+ diff_new = abs(freq - freq_avail[i]);
+ if (diff_new < diff_old) {
+ diff_old = diff_new;
+ idx = i;
+ }
+ }
+
+ switch (idx) {
+ case 0:
+ st->f_order = AD7192_SYNC4_FILTER;
+ st->mode &= ~AD7192_MODE_SINC3;
+
+ st->conf |= AD7192_CONF_CHOP;
+ break;
+ case 1:
+ st->f_order = AD7192_SYNC3_FILTER;
+ st->mode |= AD7192_MODE_SINC3;
+
+ st->conf |= AD7192_CONF_CHOP;
+ break;
+ case 2:
+ st->f_order = AD7192_NO_SYNC_FILTER;
+ st->mode &= ~AD7192_MODE_SINC3;
+
+ st->conf &= ~AD7192_CONF_CHOP;
+ break;
+ case 3:
+ st->f_order = AD7192_NO_SYNC_FILTER;
+ st->mode |= AD7192_MODE_SINC3;
+
+ st->conf &= ~AD7192_CONF_CHOP;
+ break;
+ }
+
+ ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
+ if (ret < 0)
+ return ret;
+
+ return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
+}
+
+static int ad7192_get_3db_filter_freq(struct ad7192_state *st)
+{
+ unsigned int fadc;
+
+ fadc = DIV_ROUND_CLOSEST(st->fclk,
+ st->f_order * AD7192_MODE_RATE(st->mode));
+
+ if (st->conf & AD7192_CONF_CHOP)
+ return DIV_ROUND_CLOSEST(fadc * 240, 1024);
+ if (st->mode & AD7192_MODE_SINC3)
+ return DIV_ROUND_CLOSEST(fadc * 272, 1024);
+ else
+ return DIV_ROUND_CLOSEST(fadc * 230, 1024);
+}
+
static int ad7192_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@@ -483,6 +587,10 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val = st->fclk /
(st->f_order * 1024 * AD7192_MODE_RATE(st->mode));
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *val = ad7192_get_3db_filter_freq(st);
+ *val2 = 1000;
+ return IIO_VAL_FRACTIONAL;
}
return -EINVAL;
@@ -537,6 +645,9 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
st->mode |= AD7192_MODE_RATE(div);
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
break;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
+ break;
default:
ret = -EINVAL;
}
@@ -555,6 +666,8 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
@@ -655,6 +768,8 @@ static int ad7192_channels_config(struct iio_dev *indio_dev)
for (i = 0; i < indio_dev->num_channels; i++) {
*chan = channels[i];
+ chan->info_mask_shared_by_all |=
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY);
if (chan->type != IIO_TEMP)
chan->info_mask_shared_by_type_available |=
BIT(IIO_CHAN_INFO_SCALE);
@@ -666,16 +781,10 @@ static int ad7192_channels_config(struct iio_dev *indio_dev)
static int ad7192_probe(struct spi_device *spi)
{
- const struct ad7192_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad7192_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
- if (!pdata) {
- dev_err(&spi->dev, "no platform data?\n");
- return -ENODEV;
- }
-
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ?\n");
return -ENODEV;
@@ -713,12 +822,10 @@ static int ad7192_probe(struct spi_device *spi)
voltage_uv = regulator_get_voltage(st->avdd);
- if (pdata->vref_mv)
- st->int_vref_mv = pdata->vref_mv;
- else if (voltage_uv)
+ if (voltage_uv)
st->int_vref_mv = voltage_uv / 1000;
else
- dev_warn(&spi->dev, "reference voltage undefined\n");
+ dev_err(&spi->dev, "Device tree error, reference voltage undefined\n");
spi_set_drvdata(spi, indio_dev);
st->devid = spi_get_device_id(spi)->driver_data;
@@ -809,11 +916,23 @@ static const struct spi_device_id ad7192_id[] = {
{"ad7195", ID_AD7195},
{}
};
+
MODULE_DEVICE_TABLE(spi, ad7192_id);
+static const struct of_device_id ad7192_of_match[] = {
+ { .compatible = "adi,ad7190" },
+ { .compatible = "adi,ad7192" },
+ { .compatible = "adi,ad7193" },
+ { .compatible = "adi,ad7195" },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, ad7192_of_match);
+
static struct spi_driver ad7192_driver = {
.driver = {
.name = "ad7192",
+ .of_match_table = ad7192_of_match,
},
.probe = ad7192_probe,
.remove = ad7192_remove,
diff --git a/drivers/staging/iio/adc/ad7192.h b/drivers/staging/iio/adc/ad7192.h
deleted file mode 100644
index f3669e1df084..000000000000
--- a/drivers/staging/iio/adc/ad7192.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * AD7190 AD7192 AD7195 SPI ADC driver
- *
- * Copyright 2011 Analog Devices Inc.
- */
-#ifndef IIO_ADC_AD7192_H_
-#define IIO_ADC_AD7192_H_
-
-/*
- * TODO: struct ad7192_platform_data needs to go into include/linux/iio
- */
-
-/**
- * struct ad7192_platform_data - platform/board specific information
- * @vref_mv: the external reference voltage in millivolt
- * @clock_source_sel: [0..3]
- * 0 External 4.92 MHz clock connected from MCLK1 to MCLK2
- * 1 External Clock applied to MCLK2
- * 2 Internal 4.92 MHz Clock not available at the MCLK2 pin
- * 3 Internal 4.92 MHz Clock available at the MCLK2 pin
- * @ext_clk_Hz: the external clock frequency in Hz, if not set
- * the driver uses the internal clock (16.776 MHz)
- * @refin2_en: REFIN1/REFIN2 Reference Select (AD7190/2 only)
- * @rej60_en: 50/60Hz notch filter enable
- * @sinc3_en: SINC3 filter enable (default SINC4)
- * @chop_en: CHOP mode enable
- * @buf_en: buffered input mode enable
- * @unipolar_en: unipolar mode enable
- * @burnout_curr_en: constant current generators on AIN(+|-) enable
- */
-
-struct ad7192_platform_data {
- u16 vref_mv;
-};
-
-#endif /* IIO_ADC_AD7192_H_ */
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index 0c1bd108c386..4b25a3a314ed 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -671,7 +671,7 @@ static int ad2s1210_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(ad2s1210_channels);
indio_dev->name = spi_get_device_id(spi)->name;
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(&spi->dev, indio_dev);
if (ret)
return ret;
@@ -683,15 +683,6 @@ static int ad2s1210_probe(struct spi_device *spi)
return 0;
}
-static int ad2s1210_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
-
- iio_device_unregister(indio_dev);
-
- return 0;
-}
-
static const struct of_device_id ad2s1210_of_match[] = {
{ .compatible = "adi,ad2s1210", },
{ }
@@ -710,7 +701,6 @@ static struct spi_driver ad2s1210_driver = {
.of_match_table = of_match_ptr(ad2s1210_of_match),
},
.probe = ad2s1210_probe,
- .remove = ad2s1210_remove,
.id_table = ad2s1210_id,
};
module_spi_driver(ad2s1210_driver);
diff --git a/drivers/staging/isdn/hysdn/Kconfig b/drivers/staging/isdn/hysdn/Kconfig
index 1971ef850c9a..4c8a9283b9dd 100644
--- a/drivers/staging/isdn/hysdn/Kconfig
+++ b/drivers/staging/isdn/hysdn/Kconfig
@@ -5,7 +5,7 @@ config HYSDN
help
Say Y here if you have one of Hypercope's active PCI ISDN cards
Champ, Ergo and Metro. You will then get a module called hysdn.
- Please read the file <file:Documentation/isdn/README.hysdn> for more
+ Please read the file <file:Documentation/isdn/hysdn.rst> for more
information.
config HYSDN_CAPI
diff --git a/drivers/staging/isdn/hysdn/hysdn_net.c b/drivers/staging/isdn/hysdn/hysdn_net.c
index bea37ae30ebb..dcb9ef7a2651 100644
--- a/drivers/staging/isdn/hysdn/hysdn_net.c
+++ b/drivers/staging/isdn/hysdn/hysdn_net.c
@@ -286,7 +286,7 @@ hysdn_net_create(hysdn_card *card)
if (card->debug_flags & LOG_NET_INIT)
hysdn_addlog(card, "network device created");
- return (0); /* and return success */
+ return 0; /* and return success */
} /* hysdn_net_create */
/***************************************************************************/
diff --git a/drivers/staging/isdn/hysdn/hysdn_procconf.c b/drivers/staging/isdn/hysdn/hysdn_procconf.c
index 73079213ec94..48afd9f5316e 100644
--- a/drivers/staging/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/staging/isdn/hysdn/hysdn_procconf.c
@@ -382,7 +382,7 @@ hysdn_procconf_init(void)
}
printk(KERN_NOTICE "HYSDN: procfs initialised\n");
- return (0);
+ return 0;
} /* hysdn_procconf_init */
/*************************************************************************************/
diff --git a/drivers/staging/kpc2000/kpc2000/cell_probe.c b/drivers/staging/kpc2000/kpc2000/cell_probe.c
index c124a836db27..738122afc2ae 100644
--- a/drivers/staging/kpc2000/kpc2000/cell_probe.c
+++ b/drivers/staging/kpc2000/kpc2000/cell_probe.c
@@ -53,15 +53,15 @@ struct core_table_entry {
static
void parse_core_table_entry_v0(struct core_table_entry *cte, const u64 read_val)
{
- cte->type = ((read_val & 0xFFF0000000000000) >> 52);
- cte->offset = ((read_val & 0x00000000FFFF0000) >> 16) * 4096;
- cte->length = ((read_val & 0x0000FFFF00000000) >> 32) * 8;
- cte->s2c_dma_present = ((read_val & 0x0008000000000000) >> 51);
- cte->s2c_dma_channel_num = ((read_val & 0x0007000000000000) >> 48);
- cte->c2s_dma_present = ((read_val & 0x0000000000008000) >> 15);
- cte->c2s_dma_channel_num = ((read_val & 0x0000000000007000) >> 12);
- cte->irq_count = ((read_val & 0x0000000000000C00) >> 10);
- cte->irq_base_num = ((read_val & 0x00000000000003F8) >> 3);
+ cte->type = ((read_val & 0xFFF0000000000000UL) >> 52);
+ cte->offset = ((read_val & 0x00000000FFFF0000UL) >> 16) * 4096;
+ cte->length = ((read_val & 0x0000FFFF00000000UL) >> 32) * 8;
+ cte->s2c_dma_present = ((read_val & 0x0008000000000000UL) >> 51);
+ cte->s2c_dma_channel_num = ((read_val & 0x0007000000000000UL) >> 48);
+ cte->c2s_dma_present = ((read_val & 0x0000000000008000UL) >> 15);
+ cte->c2s_dma_channel_num = ((read_val & 0x0000000000007000UL) >> 12);
+ cte->irq_count = ((read_val & 0x0000000000000C00UL) >> 10);
+ cte->irq_base_num = ((read_val & 0x00000000000003F8UL) >> 3);
}
static
diff --git a/drivers/staging/kpc2000/kpc2000/core.c b/drivers/staging/kpc2000/kpc2000/core.c
index cb05cca687e1..0a23727d0dc3 100644
--- a/drivers/staging/kpc2000/kpc2000/core.c
+++ b/drivers/staging/kpc2000/kpc2000/core.c
@@ -205,7 +205,7 @@ static void wait_and_read_ssid(struct kp2000_device *pcard)
u64 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
unsigned long timeout;
- if (read_val & 0x8000000000000000) {
+ if (read_val & 0x8000000000000000UL) {
pcard->ssid = read_val;
return;
}
@@ -213,7 +213,7 @@ static void wait_and_read_ssid(struct kp2000_device *pcard)
timeout = jiffies + (HZ * 2);
do {
read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
- if (read_val & 0x8000000000000000) {
+ if (read_val & 0x8000000000000000UL) {
pcard->ssid = read_val;
return;
}
@@ -241,16 +241,16 @@ static int read_system_regs(struct kp2000_device *pcard)
}
read_val = readq(pcard->sysinfo_regs_base + REG_CARD_ID_AND_BUILD);
- pcard->card_id = (read_val & 0xFFFFFFFF00000000) >> 32;
- pcard->build_version = (read_val & 0x00000000FFFFFFFF) >> 0;
+ pcard->card_id = (read_val & 0xFFFFFFFF00000000UL) >> 32;
+ pcard->build_version = (read_val & 0x00000000FFFFFFFFUL) >> 0;
read_val = readq(pcard->sysinfo_regs_base + REG_DATE_AND_TIME_STAMPS);
- pcard->build_datestamp = (read_val & 0xFFFFFFFF00000000) >> 32;
- pcard->build_timestamp = (read_val & 0x00000000FFFFFFFF) >> 0;
+ pcard->build_datestamp = (read_val & 0xFFFFFFFF00000000UL) >> 32;
+ pcard->build_timestamp = (read_val & 0x00000000FFFFFFFFUL) >> 0;
read_val = readq(pcard->sysinfo_regs_base + REG_CORE_TABLE_OFFSET);
- pcard->core_table_length = (read_val & 0xFFFFFFFF00000000) >> 32;
- pcard->core_table_offset = (read_val & 0x00000000FFFFFFFF) >> 0;
+ pcard->core_table_length = (read_val & 0xFFFFFFFF00000000UL) >> 32;
+ pcard->core_table_offset = (read_val & 0x00000000FFFFFFFFUL) >> 0;
wait_and_read_ssid(pcard);
@@ -401,7 +401,7 @@ static int kp2000_pcie_probe(struct pci_dev *pdev,
goto err_release_dma;
// Disable all "user" interrupts because they're not used yet.
- writeq(0xFFFFFFFFFFFFFFFF,
+ writeq(0xFFFFFFFFFFFFFFFFUL,
pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
// let the card master PCIe
diff --git a/drivers/staging/kpc2000/kpc2000_i2c.c b/drivers/staging/kpc2000/kpc2000_i2c.c
index b108da4ac633..bc02534d8dc3 100644
--- a/drivers/staging/kpc2000/kpc2000_i2c.c
+++ b/drivers/staging/kpc2000/kpc2000_i2c.c
@@ -123,9 +123,9 @@ struct i2c_device {
// FIXME!
#undef inb_p
-#define inb_p(a) readq((void *)a)
+#define inb_p(a) readq((void __iomem *)a)
#undef outb_p
-#define outb_p(d, a) writeq(d, (void *)a)
+#define outb_p(d, a) writeq(d, (void __iomem *)a)
/* Make sure the SMBus host is ready to start transmitting.
* Return 0 if it is, -EBUSY if it is not.
diff --git a/drivers/staging/kpc2000/kpc2000_spi.c b/drivers/staging/kpc2000/kpc2000_spi.c
index 35ac1d7070b3..3be33c450cab 100644
--- a/drivers/staging/kpc2000/kpc2000_spi.c
+++ b/drivers/staging/kpc2000/kpc2000_spi.c
@@ -412,8 +412,7 @@ kp_spi_cleanup(struct spi_device *spidev)
{
struct kp_spi_controller_state *cs = spidev->controller_state;
- if (cs)
- kfree(cs);
+ kfree(cs);
}
/******************
diff --git a/drivers/staging/kpc2000/kpc_dma/fileops.c b/drivers/staging/kpc2000/kpc_dma/fileops.c
index 48ca88bc6b0b..cb52bd9a6d2f 100644
--- a/drivers/staging/kpc2000/kpc_dma/fileops.c
+++ b/drivers/staging/kpc2000/kpc_dma/fileops.c
@@ -146,15 +146,15 @@ static int kpc_dma_transfer(struct dev_private_data *priv,
card_addr += desc->DescByteCount;
dma_addr = sg_dma_address(sg) + (p * 0x80000);
- desc->DescSystemAddrLS = (dma_addr & 0x00000000FFFFFFFF) >> 0;
- desc->DescSystemAddrMS = (dma_addr & 0xFFFFFFFF00000000) >> 32;
+ desc->DescSystemAddrLS = (dma_addr & 0x00000000FFFFFFFFUL) >> 0;
+ desc->DescSystemAddrMS = (dma_addr & 0xFFFFFFFF00000000UL) >> 32;
user_ctl = acd->priv->user_ctl;
if (i == acd->mapped_entry_count-1 && p == pcnt-1) {
user_ctl = acd->priv->user_ctl_last;
}
- desc->DescUserControlLS = (user_ctl & 0x00000000FFFFFFFF) >> 0;
- desc->DescUserControlMS = (user_ctl & 0xFFFFFFFF00000000) >> 32;
+ desc->DescUserControlLS = (user_ctl & 0x00000000FFFFFFFFUL) >> 0;
+ desc->DescUserControlMS = (user_ctl & 0xFFFFFFFF00000000UL) >> 32;
if (i == acd->mapped_entry_count-1 && p == pcnt-1)
desc->acd = acd;
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 534d85d6c5e3..642adc4c24d2 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -22,10 +22,6 @@ if STAGING_MEDIA && MEDIA_SUPPORT
# Please keep them in alphabetic order
source "drivers/staging/media/allegro-dvt/Kconfig"
-source "drivers/staging/media/bcm2048/Kconfig"
-
-source "drivers/staging/media/davinci_vpfe/Kconfig"
-
source "drivers/staging/media/hantro/Kconfig"
source "drivers/staging/media/imx/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index c486298194da..2f1711a8aeed 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro-dvt/
-obj-$(CONFIG_I2C_BCM2048) += bcm2048/
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/
-obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_VIDEO_SUNXI) += sunxi/
diff --git a/drivers/staging/media/allegro-dvt/allegro-core.c b/drivers/staging/media/allegro-dvt/allegro-core.c
index f050c7347fd5..6f0cd0784786 100644
--- a/drivers/staging/media/allegro-dvt/allegro-core.c
+++ b/drivers/staging/media/allegro-dvt/allegro-core.c
@@ -2947,10 +2947,8 @@ static int allegro_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get irq resource\n");
+ if (irq < 0)
return irq;
- }
ret = devm_request_threaded_irq(&pdev->dev, irq,
allegro_hardirq,
allegro_irq_thread,
diff --git a/drivers/staging/media/bcm2048/Kconfig b/drivers/staging/media/bcm2048/Kconfig
deleted file mode 100644
index ab2d50cac140..000000000000
--- a/drivers/staging/media/bcm2048/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Multimedia Video device configuration
-#
-
-config I2C_BCM2048
- tristate "Broadcom BCM2048 FM Radio Receiver support"
- depends on I2C && VIDEO_V4L2 && RADIO_ADAPTERS
- help
- Say Y here if you want support to BCM2048 FM Radio Receiver.
- This device driver supports only i2c bus.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-bcm2048.
diff --git a/drivers/staging/media/bcm2048/Makefile b/drivers/staging/media/bcm2048/Makefile
deleted file mode 100644
index f42056848dc6..000000000000
--- a/drivers/staging/media/bcm2048/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_I2C_BCM2048) += radio-bcm2048.o
diff --git a/drivers/staging/media/bcm2048/TODO b/drivers/staging/media/bcm2048/TODO
deleted file mode 100644
index 6bee2a2dad68..000000000000
--- a/drivers/staging/media/bcm2048/TODO
+++ /dev/null
@@ -1,24 +0,0 @@
-TODO:
-
-From the initial code review:
-
-The main thing you need to do is to implement all the controls using the
-control framework (see Documentation/media/kapi/v4l2-controls.rst).
-Most drivers are by now converted to the control framework, so you will
-find many examples of how to do this in drivers/media/radio.
-
-The sysfs stuff should be replaced by controls as well. A lot of the RDS
-support is now available as controls (although there may well be some
-missing features, but that is easy enough to add). Since the RDS data is
-actually read() from the device I am not sure whether the RDS
-properties/controls should be there at all.
-
-Correct Coding Style, as this driver also violates several Style
-rules, and do evil tricks, like returning from a function inside a
-macro.
-
-Finally this driver should probably be split up into two parts: one
-v4l2_subdev-based core driver and one platform driver. See e.g.
-radio-si4713/si4713-i2c.c as a good example. But I would wait with that
-until the rest of the driver is cleaned up. Then I have a better idea of
-whether this is necessary or not.
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
deleted file mode 100644
index 2c60a1fb6350..000000000000
--- a/drivers/staging/media/bcm2048/radio-bcm2048.c
+++ /dev/null
@@ -1,2689 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * drivers/staging/media/radio-bcm2048.c
- *
- * Driver for I2C Broadcom BCM2048 FM Radio Receiver:
- *
- * Copyright (C) Nokia Corporation
- * Contact: Eero Nurkkala <ext-eero.nurkkala@nokia.com>
- *
- * Copyright (C) Nils Faerber <nils.faerber@kernelconcepts.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- */
-
-/*
- * History:
- * Eero Nurkkala <ext-eero.nurkkala@nokia.com>
- * Version 0.0.1
- * - Initial implementation
- * 2010-02-21 Nils Faerber <nils.faerber@kernelconcepts.de>
- * Version 0.0.2
- * - Add support for interrupt driven rds data reading
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include "radio-bcm2048.h"
-
-/* driver definitions */
-#define BCM2048_DRIVER_AUTHOR "Eero Nurkkala <ext-eero.nurkkala@nokia.com>"
-#define BCM2048_DRIVER_NAME BCM2048_NAME
-#define BCM2048_DRIVER_CARD "Broadcom bcm2048 FM Radio Receiver"
-#define BCM2048_DRIVER_DESC "I2C driver for BCM2048 FM Radio Receiver"
-
-/* I2C Control Registers */
-#define BCM2048_I2C_FM_RDS_SYSTEM 0x00
-#define BCM2048_I2C_FM_CTRL 0x01
-#define BCM2048_I2C_RDS_CTRL0 0x02
-#define BCM2048_I2C_RDS_CTRL1 0x03
-#define BCM2048_I2C_FM_AUDIO_PAUSE 0x04
-#define BCM2048_I2C_FM_AUDIO_CTRL0 0x05
-#define BCM2048_I2C_FM_AUDIO_CTRL1 0x06
-#define BCM2048_I2C_FM_SEARCH_CTRL0 0x07
-#define BCM2048_I2C_FM_SEARCH_CTRL1 0x08
-#define BCM2048_I2C_FM_SEARCH_TUNE_MODE 0x09
-#define BCM2048_I2C_FM_FREQ0 0x0a
-#define BCM2048_I2C_FM_FREQ1 0x0b
-#define BCM2048_I2C_FM_AF_FREQ0 0x0c
-#define BCM2048_I2C_FM_AF_FREQ1 0x0d
-#define BCM2048_I2C_FM_CARRIER 0x0e
-#define BCM2048_I2C_FM_RSSI 0x0f
-#define BCM2048_I2C_FM_RDS_MASK0 0x10
-#define BCM2048_I2C_FM_RDS_MASK1 0x11
-#define BCM2048_I2C_FM_RDS_FLAG0 0x12
-#define BCM2048_I2C_FM_RDS_FLAG1 0x13
-#define BCM2048_I2C_RDS_WLINE 0x14
-#define BCM2048_I2C_RDS_BLKB_MATCH0 0x16
-#define BCM2048_I2C_RDS_BLKB_MATCH1 0x17
-#define BCM2048_I2C_RDS_BLKB_MASK0 0x18
-#define BCM2048_I2C_RDS_BLKB_MASK1 0x19
-#define BCM2048_I2C_RDS_PI_MATCH0 0x1a
-#define BCM2048_I2C_RDS_PI_MATCH1 0x1b
-#define BCM2048_I2C_RDS_PI_MASK0 0x1c
-#define BCM2048_I2C_RDS_PI_MASK1 0x1d
-#define BCM2048_I2C_SPARE1 0x20
-#define BCM2048_I2C_SPARE2 0x21
-#define BCM2048_I2C_FM_RDS_REV 0x28
-#define BCM2048_I2C_SLAVE_CONFIGURATION 0x29
-#define BCM2048_I2C_RDS_DATA 0x80
-#define BCM2048_I2C_FM_BEST_TUNE_MODE 0x90
-
-/* BCM2048_I2C_FM_RDS_SYSTEM */
-#define BCM2048_FM_ON 0x01
-#define BCM2048_RDS_ON 0x02
-
-/* BCM2048_I2C_FM_CTRL */
-#define BCM2048_BAND_SELECT 0x01
-#define BCM2048_STEREO_MONO_AUTO_SELECT 0x02
-#define BCM2048_STEREO_MONO_MANUAL_SELECT 0x04
-#define BCM2048_STEREO_MONO_BLEND_SWITCH 0x08
-#define BCM2048_HI_LO_INJECTION 0x10
-
-/* BCM2048_I2C_RDS_CTRL0 */
-#define BCM2048_RBDS_RDS_SELECT 0x01
-#define BCM2048_FLUSH_FIFO 0x02
-
-/* BCM2048_I2C_FM_AUDIO_PAUSE */
-#define BCM2048_AUDIO_PAUSE_RSSI_TRESH 0x0f
-#define BCM2048_AUDIO_PAUSE_DURATION 0xf0
-
-/* BCM2048_I2C_FM_AUDIO_CTRL0 */
-#define BCM2048_RF_MUTE 0x01
-#define BCM2048_MANUAL_MUTE 0x02
-#define BCM2048_DAC_OUTPUT_LEFT 0x04
-#define BCM2048_DAC_OUTPUT_RIGHT 0x08
-#define BCM2048_AUDIO_ROUTE_DAC 0x10
-#define BCM2048_AUDIO_ROUTE_I2S 0x20
-#define BCM2048_DE_EMPHASIS_SELECT 0x40
-#define BCM2048_AUDIO_BANDWIDTH_SELECT 0x80
-
-/* BCM2048_I2C_FM_SEARCH_CTRL0 */
-#define BCM2048_SEARCH_RSSI_THRESHOLD 0x7f
-#define BCM2048_SEARCH_DIRECTION 0x80
-
-/* BCM2048_I2C_FM_SEARCH_TUNE_MODE */
-#define BCM2048_FM_AUTO_SEARCH 0x03
-
-/* BCM2048_I2C_FM_RSSI */
-#define BCM2048_RSSI_VALUE 0xff
-
-/* BCM2048_I2C_FM_RDS_MASK0 */
-/* BCM2048_I2C_FM_RDS_MASK1 */
-#define BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED 0x01
-#define BCM2048_FM_FLAG_SEARCH_TUNE_FAIL 0x02
-#define BCM2048_FM_FLAG_RSSI_LOW 0x04
-#define BCM2048_FM_FLAG_CARRIER_ERROR_HIGH 0x08
-#define BCM2048_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10
-#define BCM2048_FLAG_STEREO_DETECTED 0x20
-#define BCM2048_FLAG_STEREO_ACTIVE 0x40
-
-/* BCM2048_I2C_RDS_DATA */
-#define BCM2048_SLAVE_ADDRESS 0x3f
-#define BCM2048_SLAVE_ENABLE 0x80
-
-/* BCM2048_I2C_FM_BEST_TUNE_MODE */
-#define BCM2048_BEST_TUNE_MODE 0x80
-
-#define BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED 0x01
-#define BCM2048_FM_FLAG_SEARCH_TUNE_FAIL 0x02
-#define BCM2048_FM_FLAG_RSSI_LOW 0x04
-#define BCM2048_FM_FLAG_CARRIER_ERROR_HIGH 0x08
-#define BCM2048_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10
-#define BCM2048_FLAG_STEREO_DETECTED 0x20
-#define BCM2048_FLAG_STEREO_ACTIVE 0x40
-
-#define BCM2048_RDS_FLAG_FIFO_WLINE 0x02
-#define BCM2048_RDS_FLAG_B_BLOCK_MATCH 0x08
-#define BCM2048_RDS_FLAG_SYNC_LOST 0x10
-#define BCM2048_RDS_FLAG_PI_MATCH 0x20
-
-#define BCM2048_RDS_MARK_END_BYTE0 0x7C
-#define BCM2048_RDS_MARK_END_BYTEN 0xFF
-
-#define BCM2048_FM_FLAGS_ALL (FM_FLAG_SEARCH_TUNE_FINISHED | \
- FM_FLAG_SEARCH_TUNE_FAIL | \
- FM_FLAG_RSSI_LOW | \
- FM_FLAG_CARRIER_ERROR_HIGH | \
- FM_FLAG_AUDIO_PAUSE_INDICATION | \
- FLAG_STEREO_DETECTED | FLAG_STEREO_ACTIVE)
-
-#define BCM2048_RDS_FLAGS_ALL (RDS_FLAG_FIFO_WLINE | \
- RDS_FLAG_B_BLOCK_MATCH | \
- RDS_FLAG_SYNC_LOST | RDS_FLAG_PI_MATCH)
-
-#define BCM2048_DEFAULT_TIMEOUT 1500
-#define BCM2048_AUTO_SEARCH_TIMEOUT 3000
-
-#define BCM2048_FREQDEV_UNIT 10000
-#define BCM2048_FREQV4L2_MULTI 625
-#define dev_to_v4l2(f) (((f) * BCM2048_FREQDEV_UNIT) / BCM2048_FREQV4L2_MULTI)
-#define v4l2_to_dev(f) (((f) * BCM2048_FREQV4L2_MULTI) / BCM2048_FREQDEV_UNIT)
-
-#define msb(x) ((u8)((u16)(x) >> 8))
-#define lsb(x) ((u8)((u16)(x) & 0x00FF))
-#define compose_u16(msb, lsb) (((u16)(msb) << 8) | (lsb))
-
-#define BCM2048_DEFAULT_POWERING_DELAY 20
-#define BCM2048_DEFAULT_REGION 0x02
-#define BCM2048_DEFAULT_MUTE 0x01
-#define BCM2048_DEFAULT_RSSI_THRESHOLD 0x64
-#define BCM2048_DEFAULT_RDS_WLINE 0x7E
-
-#define BCM2048_FM_SEARCH_INACTIVE 0x00
-#define BCM2048_FM_PRE_SET_MODE 0x01
-#define BCM2048_FM_AUTO_SEARCH_MODE 0x02
-#define BCM2048_FM_AF_JUMP_MODE 0x03
-
-#define BCM2048_FREQUENCY_BASE 64000
-
-#define BCM2048_POWER_ON 0x01
-#define BCM2048_POWER_OFF 0x00
-
-#define BCM2048_ITEM_ENABLED 0x01
-#define BCM2048_SEARCH_DIRECTION_UP 0x01
-
-#define BCM2048_DE_EMPHASIS_75us 75
-#define BCM2048_DE_EMPHASIS_50us 50
-
-#define BCM2048_SCAN_FAIL 0x00
-#define BCM2048_SCAN_OK 0x01
-
-#define BCM2048_FREQ_ERROR_FLOOR -20
-#define BCM2048_FREQ_ERROR_ROOF 20
-
-/* -60 dB is reported as full signal strength */
-#define BCM2048_RSSI_LEVEL_BASE -60
-#define BCM2048_RSSI_LEVEL_ROOF -100
-#define BCM2048_RSSI_LEVEL_ROOF_NEG 100
-#define BCM2048_SIGNAL_MULTIPLIER (0xFFFF / \
- (BCM2048_RSSI_LEVEL_ROOF_NEG + \
- BCM2048_RSSI_LEVEL_BASE))
-
-#define BCM2048_RDS_FIFO_DUPLE_SIZE 0x03
-#define BCM2048_RDS_CRC_MASK 0x0F
-#define BCM2048_RDS_CRC_NONE 0x00
-#define BCM2048_RDS_CRC_MAX_2BITS 0x04
-#define BCM2048_RDS_CRC_LEAST_2BITS 0x08
-#define BCM2048_RDS_CRC_UNRECOVARABLE 0x0C
-
-#define BCM2048_RDS_BLOCK_MASK 0xF0
-#define BCM2048_RDS_BLOCK_A 0x00
-#define BCM2048_RDS_BLOCK_B 0x10
-#define BCM2048_RDS_BLOCK_C 0x20
-#define BCM2048_RDS_BLOCK_D 0x30
-#define BCM2048_RDS_BLOCK_C_SCORED 0x40
-#define BCM2048_RDS_BLOCK_E 0x60
-
-#define BCM2048_RDS_RT 0x20
-#define BCM2048_RDS_PS 0x00
-
-#define BCM2048_RDS_GROUP_AB_MASK 0x08
-#define BCM2048_RDS_GROUP_A 0x00
-#define BCM2048_RDS_GROUP_B 0x08
-
-#define BCM2048_RDS_RT_AB_MASK 0x10
-#define BCM2048_RDS_RT_A 0x00
-#define BCM2048_RDS_RT_B 0x10
-#define BCM2048_RDS_RT_INDEX 0x0F
-
-#define BCM2048_RDS_PS_INDEX 0x03
-
-struct rds_info {
- u16 rds_pi;
-#define BCM2048_MAX_RDS_RT (64 + 1)
- u8 rds_rt[BCM2048_MAX_RDS_RT];
- u8 rds_rt_group_b;
- u8 rds_rt_ab;
-#define BCM2048_MAX_RDS_PS (8 + 1)
- u8 rds_ps[BCM2048_MAX_RDS_PS];
- u8 rds_ps_group;
- u8 rds_ps_group_cnt;
-#define BCM2048_MAX_RDS_RADIO_TEXT 255
- u8 radio_text[BCM2048_MAX_RDS_RADIO_TEXT + 3];
- u8 text_len;
-};
-
-struct region_info {
- u32 bottom_frequency;
- u32 top_frequency;
- u8 deemphasis;
- u8 channel_spacing;
- u8 region;
-};
-
-struct bcm2048_device {
- struct i2c_client *client;
- struct video_device videodev;
- struct work_struct work;
- struct completion compl;
- struct mutex mutex;
- struct bcm2048_platform_data *platform_data;
- struct rds_info rds_info;
- struct region_info region_info;
- u16 frequency;
- u8 cache_fm_rds_system;
- u8 cache_fm_ctrl;
- u8 cache_fm_audio_ctrl0;
- u8 cache_fm_search_ctrl0;
- u8 power_state;
- u8 rds_state;
- u8 fifo_size;
- u8 scan_state;
- u8 mute_state;
-
- /* for rds data device read */
- wait_queue_head_t read_queue;
- unsigned int users;
- unsigned char rds_data_available;
- unsigned int rd_index;
-};
-
-static int radio_nr = -1; /* radio device minor (-1 ==> auto assign) */
-module_param(radio_nr, int, 0000);
-MODULE_PARM_DESC(radio_nr,
- "Minor number for radio device (-1 ==> auto assign)");
-
-static const struct region_info region_configs[] = {
- /* USA */
- {
- .channel_spacing = 20,
- .bottom_frequency = 87500,
- .top_frequency = 108000,
- .deemphasis = 75,
- .region = 0,
- },
- /* Australia */
- {
- .channel_spacing = 20,
- .bottom_frequency = 87500,
- .top_frequency = 108000,
- .deemphasis = 50,
- .region = 1,
- },
- /* Europe */
- {
- .channel_spacing = 10,
- .bottom_frequency = 87500,
- .top_frequency = 108000,
- .deemphasis = 50,
- .region = 2,
- },
- /* Japan */
- {
- .channel_spacing = 10,
- .bottom_frequency = 76000,
- .top_frequency = 90000,
- .deemphasis = 50,
- .region = 3,
- },
-};
-
-/*
- * I2C Interface read / write
- */
-static int bcm2048_send_command(struct bcm2048_device *bdev, unsigned int reg,
- unsigned int value)
-{
- struct i2c_client *client = bdev->client;
- u8 data[2];
-
- if (!bdev->power_state) {
- dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n");
- return -EIO;
- }
-
- data[0] = reg & 0xff;
- data[1] = value & 0xff;
-
- if (i2c_master_send(client, data, 2) == 2)
- return 0;
-
- dev_err(&bdev->client->dev, "BCM I2C error!\n");
- dev_err(&bdev->client->dev, "Is Bluetooth up and running?\n");
- return -EIO;
-}
-
-static int bcm2048_recv_command(struct bcm2048_device *bdev, unsigned int reg,
- u8 *value)
-{
- struct i2c_client *client = bdev->client;
-
- if (!bdev->power_state) {
- dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n");
- return -EIO;
- }
-
- value[0] = i2c_smbus_read_byte_data(client, reg & 0xff);
-
- return 0;
-}
-
-static int bcm2048_recv_duples(struct bcm2048_device *bdev, unsigned int reg,
- u8 *value, u8 duples)
-{
- struct i2c_client *client = bdev->client;
- struct i2c_adapter *adap = client->adapter;
- struct i2c_msg msg[2];
- u8 buf;
-
- if (!bdev->power_state) {
- dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n");
- return -EIO;
- }
-
- buf = reg & 0xff;
-
- msg[0].addr = client->addr;
- msg[0].flags = client->flags & I2C_M_TEN;
- msg[0].len = 1;
- msg[0].buf = &buf;
-
- msg[1].addr = client->addr;
- msg[1].flags = client->flags & I2C_M_TEN;
- msg[1].flags |= I2C_M_RD;
- msg[1].len = duples;
- msg[1].buf = value;
-
- return i2c_transfer(adap, msg, 2);
-}
-
-/*
- * BCM2048 - I2C register programming helpers
- */
-static int bcm2048_set_power_state(struct bcm2048_device *bdev, u8 power)
-{
- int err = 0;
-
- mutex_lock(&bdev->mutex);
-
- if (power) {
- bdev->power_state = BCM2048_POWER_ON;
- bdev->cache_fm_rds_system |= BCM2048_FM_ON;
- } else {
- bdev->cache_fm_rds_system &= ~BCM2048_FM_ON;
- }
-
- /*
- * Warning! FM cannot be turned off because then
- * the I2C communications get ruined!
- * Comment off the "if (power)" when the chip works!
- */
- if (power)
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM,
- bdev->cache_fm_rds_system);
- msleep(BCM2048_DEFAULT_POWERING_DELAY);
-
- if (!power)
- bdev->power_state = BCM2048_POWER_OFF;
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_power_state(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err && (value & BCM2048_FM_ON))
- return BCM2048_POWER_ON;
-
- return err;
-}
-
-static int bcm2048_set_rds_no_lock(struct bcm2048_device *bdev, u8 rds_on)
-{
- int err;
- u8 flags;
-
- bdev->cache_fm_rds_system &= ~BCM2048_RDS_ON;
-
- if (rds_on) {
- bdev->cache_fm_rds_system |= BCM2048_RDS_ON;
- bdev->rds_state = BCM2048_RDS_ON;
- flags = BCM2048_RDS_FLAG_FIFO_WLINE;
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
- flags);
- } else {
- flags = 0;
- bdev->rds_state = 0;
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
- flags);
- memset(&bdev->rds_info, 0, sizeof(bdev->rds_info));
- }
- if (err)
- return err;
-
- return bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM,
- bdev->cache_fm_rds_system);
-}
-
-static int bcm2048_get_rds_no_lock(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, &value);
-
- if (!err && (value & BCM2048_RDS_ON))
- return BCM2048_ITEM_ENABLED;
-
- return err;
-}
-
-static int bcm2048_set_rds(struct bcm2048_device *bdev, u8 rds_on)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_set_rds_no_lock(bdev, rds_on);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_rds(struct bcm2048_device *bdev)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_get_rds_no_lock(bdev);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_rds_pi(struct bcm2048_device *bdev)
-{
- return bdev->rds_info.rds_pi;
-}
-
-static int bcm2048_set_fm_automatic_stereo_mono(struct bcm2048_device *bdev,
- u8 enabled)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- bdev->cache_fm_ctrl &= ~BCM2048_STEREO_MONO_AUTO_SELECT;
-
- if (enabled)
- bdev->cache_fm_ctrl |= BCM2048_STEREO_MONO_AUTO_SELECT;
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL,
- bdev->cache_fm_ctrl);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_set_fm_hi_lo_injection(struct bcm2048_device *bdev,
- u8 hi_lo)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- bdev->cache_fm_ctrl &= ~BCM2048_HI_LO_INJECTION;
-
- if (hi_lo)
- bdev->cache_fm_ctrl |= BCM2048_HI_LO_INJECTION;
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL,
- bdev->cache_fm_ctrl);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_fm_hi_lo_injection(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_CTRL, &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err && (value & BCM2048_HI_LO_INJECTION))
- return BCM2048_ITEM_ENABLED;
-
- return err;
-}
-
-static int bcm2048_set_fm_frequency(struct bcm2048_device *bdev, u32 frequency)
-{
- int err;
-
- if (frequency < bdev->region_info.bottom_frequency ||
- frequency > bdev->region_info.top_frequency)
- return -EDOM;
-
- frequency -= BCM2048_FREQUENCY_BASE;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ0, lsb(frequency));
- err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ1,
- msb(frequency));
-
- if (!err)
- bdev->frequency = frequency;
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_fm_frequency(struct bcm2048_device *bdev)
-{
- int err;
- u8 lsb = 0, msb = 0;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_FREQ0, &lsb);
- err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_FREQ1, &msb);
-
- mutex_unlock(&bdev->mutex);
-
- if (err)
- return err;
-
- err = compose_u16(msb, lsb);
- err += BCM2048_FREQUENCY_BASE;
-
- return err;
-}
-
-static int bcm2048_set_fm_af_frequency(struct bcm2048_device *bdev,
- u32 frequency)
-{
- int err;
-
- if (frequency < bdev->region_info.bottom_frequency ||
- frequency > bdev->region_info.top_frequency)
- return -EDOM;
-
- frequency -= BCM2048_FREQUENCY_BASE;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ0,
- lsb(frequency));
- err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ1,
- msb(frequency));
- if (!err)
- bdev->frequency = frequency;
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_fm_af_frequency(struct bcm2048_device *bdev)
-{
- int err;
- u8 lsb = 0, msb = 0;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AF_FREQ0, &lsb);
- err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_AF_FREQ1, &msb);
-
- mutex_unlock(&bdev->mutex);
-
- if (err)
- return err;
-
- err = compose_u16(msb, lsb);
- err += BCM2048_FREQUENCY_BASE;
-
- return err;
-}
-
-static int bcm2048_set_fm_deemphasis(struct bcm2048_device *bdev, int d)
-{
- int err;
- u8 deemphasis;
-
- if (d == BCM2048_DE_EMPHASIS_75us)
- deemphasis = BCM2048_DE_EMPHASIS_SELECT;
- else
- deemphasis = 0;
-
- mutex_lock(&bdev->mutex);
-
- bdev->cache_fm_audio_ctrl0 &= ~BCM2048_DE_EMPHASIS_SELECT;
- bdev->cache_fm_audio_ctrl0 |= deemphasis;
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- bdev->cache_fm_audio_ctrl0);
-
- if (!err)
- bdev->region_info.deemphasis = d;
-
- mutex_unlock(&bdev->mutex);
-
- return err;
-}
-
-static int bcm2048_get_fm_deemphasis(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err) {
- if (value & BCM2048_DE_EMPHASIS_SELECT)
- return BCM2048_DE_EMPHASIS_75us;
-
- return BCM2048_DE_EMPHASIS_50us;
- }
-
- return err;
-}
-
-static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region)
-{
- int err;
- u32 new_frequency = 0;
-
- if (region >= ARRAY_SIZE(region_configs))
- return -EINVAL;
-
- mutex_lock(&bdev->mutex);
- bdev->region_info = region_configs[region];
-
- if (region_configs[region].bottom_frequency < 87500)
- bdev->cache_fm_ctrl |= BCM2048_BAND_SELECT;
- else
- bdev->cache_fm_ctrl &= ~BCM2048_BAND_SELECT;
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL,
- bdev->cache_fm_ctrl);
- if (err) {
- mutex_unlock(&bdev->mutex);
- goto done;
- }
- mutex_unlock(&bdev->mutex);
-
- if (bdev->frequency < region_configs[region].bottom_frequency ||
- bdev->frequency > region_configs[region].top_frequency)
- new_frequency = region_configs[region].bottom_frequency;
-
- if (new_frequency > 0) {
- err = bcm2048_set_fm_frequency(bdev, new_frequency);
-
- if (err)
- goto done;
- }
-
- err = bcm2048_set_fm_deemphasis(bdev,
- region_configs[region].deemphasis);
-
-done:
- return err;
-}
-
-static int bcm2048_get_region(struct bcm2048_device *bdev)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
- err = bdev->region_info.region;
- mutex_unlock(&bdev->mutex);
-
- return err;
-}
-
-static int bcm2048_set_mute(struct bcm2048_device *bdev, u16 mute)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE);
-
- if (mute)
- bdev->cache_fm_audio_ctrl0 |= (BCM2048_RF_MUTE |
- BCM2048_MANUAL_MUTE);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- bdev->cache_fm_audio_ctrl0);
-
- if (!err)
- bdev->mute_state = mute;
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_mute(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- if (bdev->power_state) {
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- &value);
- if (!err)
- err = value & (BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE);
- } else {
- err = bdev->mute_state;
- }
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_set_audio_route(struct bcm2048_device *bdev, u8 route)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- route &= (BCM2048_AUDIO_ROUTE_DAC | BCM2048_AUDIO_ROUTE_I2S);
- bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_AUDIO_ROUTE_DAC |
- BCM2048_AUDIO_ROUTE_I2S);
- bdev->cache_fm_audio_ctrl0 |= route;
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- bdev->cache_fm_audio_ctrl0);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_audio_route(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return value & (BCM2048_AUDIO_ROUTE_DAC |
- BCM2048_AUDIO_ROUTE_I2S);
-
- return err;
-}
-
-static int bcm2048_set_dac_output(struct bcm2048_device *bdev, u8 channels)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_DAC_OUTPUT_LEFT |
- BCM2048_DAC_OUTPUT_RIGHT);
- bdev->cache_fm_audio_ctrl0 |= channels;
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- bdev->cache_fm_audio_ctrl0);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_dac_output(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return value & (BCM2048_DAC_OUTPUT_LEFT |
- BCM2048_DAC_OUTPUT_RIGHT);
-
- return err;
-}
-
-static int bcm2048_set_fm_search_rssi_threshold(struct bcm2048_device *bdev,
- u8 threshold)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- threshold &= BCM2048_SEARCH_RSSI_THRESHOLD;
- bdev->cache_fm_search_ctrl0 &= ~BCM2048_SEARCH_RSSI_THRESHOLD;
- bdev->cache_fm_search_ctrl0 |= threshold;
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0,
- bdev->cache_fm_search_ctrl0);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_fm_search_rssi_threshold(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return value & BCM2048_SEARCH_RSSI_THRESHOLD;
-
- return err;
-}
-
-static int bcm2048_set_fm_search_mode_direction(struct bcm2048_device *bdev,
- u8 direction)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- bdev->cache_fm_search_ctrl0 &= ~BCM2048_SEARCH_DIRECTION;
-
- if (direction)
- bdev->cache_fm_search_ctrl0 |= BCM2048_SEARCH_DIRECTION;
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0,
- bdev->cache_fm_search_ctrl0);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_fm_search_mode_direction(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err && (value & BCM2048_SEARCH_DIRECTION))
- return BCM2048_SEARCH_DIRECTION_UP;
-
- return err;
-}
-
-static int bcm2048_set_fm_search_tune_mode(struct bcm2048_device *bdev,
- u8 mode)
-{
- int err, timeout, restart_rds = 0;
- u8 value, flags;
-
- value = mode & BCM2048_FM_AUTO_SEARCH;
-
- flags = BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED |
- BCM2048_FM_FLAG_SEARCH_TUNE_FAIL;
-
- mutex_lock(&bdev->mutex);
-
- /*
- * If RDS is enabled, and frequency is changed, RDS quits working.
- * Thus, always restart RDS if it's enabled. Moreover, RDS must
- * not be enabled while changing the frequency because it can
- * provide a race to the mutex from the workqueue handler if RDS
- * IRQ occurs while waiting for frequency changed IRQ.
- */
- if (bcm2048_get_rds_no_lock(bdev)) {
- err = bcm2048_set_rds_no_lock(bdev, 0);
- if (err)
- goto unlock;
- restart_rds = 1;
- }
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK0, flags);
-
- if (err)
- goto unlock;
-
- bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE, value);
-
- if (mode != BCM2048_FM_AUTO_SEARCH_MODE)
- timeout = BCM2048_DEFAULT_TIMEOUT;
- else
- timeout = BCM2048_AUTO_SEARCH_TIMEOUT;
-
- if (!wait_for_completion_timeout(&bdev->compl,
- msecs_to_jiffies(timeout)))
- dev_err(&bdev->client->dev, "IRQ timeout.\n");
-
- if (value)
- if (!bdev->scan_state)
- err = -EIO;
-
-unlock:
- if (restart_rds)
- err |= bcm2048_set_rds_no_lock(bdev, 1);
-
- mutex_unlock(&bdev->mutex);
-
- return err;
-}
-
-static int bcm2048_get_fm_search_tune_mode(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE,
- &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return value & BCM2048_FM_AUTO_SEARCH;
-
- return err;
-}
-
-static int bcm2048_set_rds_b_block_mask(struct bcm2048_device *bdev, u16 mask)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MASK0,
- lsb(mask));
- err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MASK1,
- msb(mask));
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_rds_b_block_mask(struct bcm2048_device *bdev)
-{
- int err;
- u8 lsb = 0, msb = 0;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MASK0, &lsb);
- err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MASK1, &msb);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return compose_u16(msb, lsb);
-
- return err;
-}
-
-static int bcm2048_set_rds_b_block_match(struct bcm2048_device *bdev,
- u16 match)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH0,
- lsb(match));
- err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH1,
- msb(match));
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_rds_b_block_match(struct bcm2048_device *bdev)
-{
- int err;
- u8 lsb = 0, msb = 0;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH0, &lsb);
- err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH1, &msb);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return compose_u16(msb, lsb);
-
- return err;
-}
-
-static int bcm2048_set_rds_pi_mask(struct bcm2048_device *bdev, u16 mask)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MASK0, lsb(mask));
- err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MASK1, msb(mask));
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_rds_pi_mask(struct bcm2048_device *bdev)
-{
- int err;
- u8 lsb = 0, msb = 0;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MASK0, &lsb);
- err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MASK1, &msb);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return compose_u16(msb, lsb);
-
- return err;
-}
-
-static int bcm2048_set_rds_pi_match(struct bcm2048_device *bdev, u16 match)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MATCH0,
- lsb(match));
- err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MATCH1,
- msb(match));
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_rds_pi_match(struct bcm2048_device *bdev)
-{
- int err;
- u8 lsb = 0, msb = 0;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MATCH0, &lsb);
- err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MATCH1, &msb);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return compose_u16(msb, lsb);
-
- return err;
-}
-
-static int bcm2048_set_fm_rds_mask(struct bcm2048_device *bdev, u16 mask)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK0, lsb(mask));
- err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, msb(mask));
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_fm_rds_mask(struct bcm2048_device *bdev)
-{
- int err;
- u8 value0 = 0, value1 = 0;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_MASK0, &value0);
- err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_MASK1, &value1);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return compose_u16(value1, value0);
-
- return err;
-}
-
-static int bcm2048_get_fm_rds_flags(struct bcm2048_device *bdev)
-{
- int err;
- u8 value0 = 0, value1 = 0;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG0, &value0);
- err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG1, &value1);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return compose_u16(value1, value0);
-
- return err;
-}
-
-static int bcm2048_get_region_bottom_frequency(struct bcm2048_device *bdev)
-{
- return bdev->region_info.bottom_frequency;
-}
-
-static int bcm2048_get_region_top_frequency(struct bcm2048_device *bdev)
-{
- return bdev->region_info.top_frequency;
-}
-
-static int bcm2048_set_fm_best_tune_mode(struct bcm2048_device *bdev, u8 mode)
-{
- int err;
- u8 value = 0;
-
- mutex_lock(&bdev->mutex);
-
- /* Perform read as the manual indicates */
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
- &value);
- value &= ~BCM2048_BEST_TUNE_MODE;
-
- if (mode)
- value |= BCM2048_BEST_TUNE_MODE;
- err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
- value);
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_fm_best_tune_mode(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
- &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err && (value & BCM2048_BEST_TUNE_MODE))
- return BCM2048_ITEM_ENABLED;
-
- return err;
-}
-
-static int bcm2048_get_fm_carrier_error(struct bcm2048_device *bdev)
-{
- int err = 0;
- s8 value;
-
- mutex_lock(&bdev->mutex);
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_CARRIER, &value);
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return value;
-
- return err;
-}
-
-static int bcm2048_get_fm_rssi(struct bcm2048_device *bdev)
-{
- int err;
- s8 value;
-
- mutex_lock(&bdev->mutex);
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RSSI, &value);
- mutex_unlock(&bdev->mutex);
-
- if (!err)
- return value;
-
- return err;
-}
-
-static int bcm2048_set_rds_wline(struct bcm2048_device *bdev, u8 wline)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_WLINE, wline);
-
- if (!err)
- bdev->fifo_size = wline;
-
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_rds_wline(struct bcm2048_device *bdev)
-{
- int err;
- u8 value;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_WLINE, &value);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err) {
- bdev->fifo_size = value;
- return value;
- }
-
- return err;
-}
-
-static int bcm2048_checkrev(struct bcm2048_device *bdev)
-{
- int err;
- u8 version;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_REV, &version);
-
- mutex_unlock(&bdev->mutex);
-
- if (!err) {
- dev_info(&bdev->client->dev, "BCM2048 Version 0x%x\n",
- version);
- return version;
- }
-
- return err;
-}
-
-static int bcm2048_get_rds_rt(struct bcm2048_device *bdev, char *data)
-{
- int err = 0, i, j = 0, ce = 0, cr = 0;
- char data_buffer[BCM2048_MAX_RDS_RT + 1];
-
- mutex_lock(&bdev->mutex);
-
- if (!bdev->rds_info.text_len) {
- err = -EINVAL;
- goto unlock;
- }
-
- for (i = 0; i < BCM2048_MAX_RDS_RT; i++) {
- if (bdev->rds_info.rds_rt[i]) {
- ce = i;
- /* Skip the carriage return */
- if (bdev->rds_info.rds_rt[i] != 0x0d) {
- data_buffer[j++] = bdev->rds_info.rds_rt[i];
- } else {
- cr = i;
- break;
- }
- }
- }
-
- if (j <= BCM2048_MAX_RDS_RT)
- data_buffer[j] = 0;
-
- for (i = 0; i < BCM2048_MAX_RDS_RT; i++) {
- if (!bdev->rds_info.rds_rt[i]) {
- if (cr && (i < cr)) {
- err = -EBUSY;
- goto unlock;
- }
- if (i < ce) {
- if (cr && (i >= cr))
- break;
- err = -EBUSY;
- goto unlock;
- }
- }
- }
-
- memcpy(data, data_buffer, sizeof(data_buffer));
-
-unlock:
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static int bcm2048_get_rds_ps(struct bcm2048_device *bdev, char *data)
-{
- int err = 0, i, j = 0;
- char data_buffer[BCM2048_MAX_RDS_PS + 1];
-
- mutex_lock(&bdev->mutex);
-
- if (!bdev->rds_info.text_len) {
- err = -EINVAL;
- goto unlock;
- }
-
- for (i = 0; i < BCM2048_MAX_RDS_PS; i++) {
- if (bdev->rds_info.rds_ps[i]) {
- data_buffer[j++] = bdev->rds_info.rds_ps[i];
- } else {
- if (i < (BCM2048_MAX_RDS_PS - 1)) {
- err = -EBUSY;
- goto unlock;
- }
- }
- }
-
- if (j <= BCM2048_MAX_RDS_PS)
- data_buffer[j] = 0;
-
- memcpy(data, data_buffer, sizeof(data_buffer));
-
-unlock:
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-static void bcm2048_parse_rds_pi(struct bcm2048_device *bdev)
-{
- int i, cnt = 0;
- u16 pi;
-
- for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
- /* Block A match, only data without crc errors taken */
- if (bdev->rds_info.radio_text[i] == BCM2048_RDS_BLOCK_A) {
- pi = (bdev->rds_info.radio_text[i + 1] << 8) +
- bdev->rds_info.radio_text[i + 2];
-
- if (!bdev->rds_info.rds_pi) {
- bdev->rds_info.rds_pi = pi;
- return;
- }
- if (pi != bdev->rds_info.rds_pi) {
- cnt++;
- if (cnt > 3) {
- bdev->rds_info.rds_pi = pi;
- cnt = 0;
- }
- } else {
- cnt = 0;
- }
- }
- }
-}
-
-static int bcm2048_rds_block_crc(struct bcm2048_device *bdev, int i)
-{
- return bdev->rds_info.radio_text[i] & BCM2048_RDS_CRC_MASK;
-}
-
-static void bcm2048_parse_rds_rt_block(struct bcm2048_device *bdev, int i,
- int index, int crc)
-{
- /* Good data will overwrite poor data */
- if (crc) {
- if (!bdev->rds_info.rds_rt[index])
- bdev->rds_info.rds_rt[index] =
- bdev->rds_info.radio_text[i + 1];
- if (!bdev->rds_info.rds_rt[index + 1])
- bdev->rds_info.rds_rt[index + 1] =
- bdev->rds_info.radio_text[i + 2];
- } else {
- bdev->rds_info.rds_rt[index] =
- bdev->rds_info.radio_text[i + 1];
- bdev->rds_info.rds_rt[index + 1] =
- bdev->rds_info.radio_text[i + 2];
- }
-}
-
-static int bcm2048_parse_rt_match_b(struct bcm2048_device *bdev, int i)
-{
- int crc, rt_id, rt_group_b, rt_ab, index = 0;
-
- crc = bcm2048_rds_block_crc(bdev, i);
-
- if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
- return -EIO;
-
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_B) {
- rt_id = bdev->rds_info.radio_text[i + 1] &
- BCM2048_RDS_BLOCK_MASK;
- rt_group_b = bdev->rds_info.radio_text[i + 1] &
- BCM2048_RDS_GROUP_AB_MASK;
- rt_ab = bdev->rds_info.radio_text[i + 2] &
- BCM2048_RDS_RT_AB_MASK;
-
- if (rt_group_b != bdev->rds_info.rds_rt_group_b) {
- memset(bdev->rds_info.rds_rt, 0,
- sizeof(bdev->rds_info.rds_rt));
- bdev->rds_info.rds_rt_group_b = rt_group_b;
- }
-
- if (rt_id == BCM2048_RDS_RT) {
- /* A to B or (vice versa), means: clear screen */
- if (rt_ab != bdev->rds_info.rds_rt_ab) {
- memset(bdev->rds_info.rds_rt, 0,
- sizeof(bdev->rds_info.rds_rt));
- bdev->rds_info.rds_rt_ab = rt_ab;
- }
-
- index = bdev->rds_info.radio_text[i + 2] &
- BCM2048_RDS_RT_INDEX;
-
- if (bdev->rds_info.rds_rt_group_b)
- index <<= 1;
- else
- index <<= 2;
-
- return index;
- }
- }
-
- return -EIO;
-}
-
-static int bcm2048_parse_rt_match_c(struct bcm2048_device *bdev, int i,
- int index)
-{
- int crc;
-
- crc = bcm2048_rds_block_crc(bdev, i);
-
- if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
- return 0;
-
- if ((index + 2) >= BCM2048_MAX_RDS_RT) {
- dev_err(&bdev->client->dev,
- "Incorrect index = %d\n", index);
- return 0;
- }
-
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_C) {
- if (bdev->rds_info.rds_rt_group_b)
- return 1;
- bcm2048_parse_rds_rt_block(bdev, i, index, crc);
- return 1;
- }
-
- return 0;
-}
-
-static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i,
- int index)
-{
- int crc;
-
- crc = bcm2048_rds_block_crc(bdev, i);
-
- if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
- return;
-
- if ((index + 4) >= BCM2048_MAX_RDS_RT) {
- dev_err(&bdev->client->dev,
- "Incorrect index = %d\n", index);
- return;
- }
-
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_D)
- bcm2048_parse_rds_rt_block(bdev, i, index + 2, crc);
-}
-
-static void bcm2048_parse_rds_rt(struct bcm2048_device *bdev)
-{
- int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0;
-
- for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
- if (match_b) {
- match_b = 0;
- index = bcm2048_parse_rt_match_b(bdev, i);
- if (index >= 0 && index <= (BCM2048_MAX_RDS_RT - 5))
- match_c = 1;
- continue;
- } else if (match_c) {
- match_c = 0;
- if (bcm2048_parse_rt_match_c(bdev, i, index))
- match_d = 1;
- continue;
- } else if (match_d) {
- match_d = 0;
- bcm2048_parse_rt_match_d(bdev, i, index);
- continue;
- }
-
- /* Skip erroneous blocks due to messed up A block altogether */
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_A) {
- crc = bcm2048_rds_block_crc(bdev, i);
- if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
- continue;
- /* Synchronize to a good RDS PI */
- if (((bdev->rds_info.radio_text[i + 1] << 8) +
- bdev->rds_info.radio_text[i + 2]) ==
- bdev->rds_info.rds_pi)
- match_b = 1;
- }
- }
-}
-
-static void bcm2048_parse_rds_ps_block(struct bcm2048_device *bdev, int i,
- int index, int crc)
-{
- /* Good data will overwrite poor data */
- if (crc) {
- if (!bdev->rds_info.rds_ps[index])
- bdev->rds_info.rds_ps[index] =
- bdev->rds_info.radio_text[i + 1];
- if (!bdev->rds_info.rds_ps[index + 1])
- bdev->rds_info.rds_ps[index + 1] =
- bdev->rds_info.radio_text[i + 2];
- } else {
- bdev->rds_info.rds_ps[index] =
- bdev->rds_info.radio_text[i + 1];
- bdev->rds_info.rds_ps[index + 1] =
- bdev->rds_info.radio_text[i + 2];
- }
-}
-
-static int bcm2048_parse_ps_match_c(struct bcm2048_device *bdev, int i,
- int index)
-{
- int crc;
-
- crc = bcm2048_rds_block_crc(bdev, i);
-
- if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
- return 0;
-
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_C)
- return 1;
-
- return 0;
-}
-
-static void bcm2048_parse_ps_match_d(struct bcm2048_device *bdev, int i,
- int index)
-{
- int crc;
-
- crc = bcm2048_rds_block_crc(bdev, i);
-
- if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
- return;
-
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_D)
- bcm2048_parse_rds_ps_block(bdev, i, index, crc);
-}
-
-static int bcm2048_parse_ps_match_b(struct bcm2048_device *bdev, int i)
-{
- int crc, index, ps_id, ps_group;
-
- crc = bcm2048_rds_block_crc(bdev, i);
-
- if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
- return -EIO;
-
- /* Block B Radio PS match */
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_B) {
- ps_id = bdev->rds_info.radio_text[i + 1] &
- BCM2048_RDS_BLOCK_MASK;
- ps_group = bdev->rds_info.radio_text[i + 1] &
- BCM2048_RDS_GROUP_AB_MASK;
-
- /*
- * Poor RSSI will lead to RDS data corruption
- * So using 3 (same) sequential values to justify major changes
- */
- if (ps_group != bdev->rds_info.rds_ps_group) {
- if (crc == BCM2048_RDS_CRC_NONE) {
- bdev->rds_info.rds_ps_group_cnt++;
- if (bdev->rds_info.rds_ps_group_cnt > 2) {
- bdev->rds_info.rds_ps_group = ps_group;
- bdev->rds_info.rds_ps_group_cnt = 0;
- dev_err(&bdev->client->dev,
- "RDS PS Group change!\n");
- } else {
- return -EIO;
- }
- } else {
- bdev->rds_info.rds_ps_group_cnt = 0;
- }
- }
-
- if (ps_id == BCM2048_RDS_PS) {
- index = bdev->rds_info.radio_text[i + 2] &
- BCM2048_RDS_PS_INDEX;
- index <<= 1;
- return index;
- }
- }
-
- return -EIO;
-}
-
-static void bcm2048_parse_rds_ps(struct bcm2048_device *bdev)
-{
- int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0;
-
- for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
- if (match_b) {
- match_b = 0;
- index = bcm2048_parse_ps_match_b(bdev, i);
- if (index >= 0 && index < (BCM2048_MAX_RDS_PS - 1))
- match_c = 1;
- continue;
- } else if (match_c) {
- match_c = 0;
- if (bcm2048_parse_ps_match_c(bdev, i, index))
- match_d = 1;
- continue;
- } else if (match_d) {
- match_d = 0;
- bcm2048_parse_ps_match_d(bdev, i, index);
- continue;
- }
-
- /* Skip erroneous blocks due to messed up A block altogether */
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_A) {
- crc = bcm2048_rds_block_crc(bdev, i);
- if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
- continue;
- /* Synchronize to a good RDS PI */
- if (((bdev->rds_info.radio_text[i + 1] << 8) +
- bdev->rds_info.radio_text[i + 2]) ==
- bdev->rds_info.rds_pi)
- match_b = 1;
- }
- }
-}
-
-static void bcm2048_rds_fifo_receive(struct bcm2048_device *bdev)
-{
- int err;
-
- mutex_lock(&bdev->mutex);
-
- err = bcm2048_recv_duples(bdev, BCM2048_I2C_RDS_DATA,
- bdev->rds_info.radio_text, bdev->fifo_size);
- if (err != 2) {
- dev_err(&bdev->client->dev, "RDS Read problem\n");
- mutex_unlock(&bdev->mutex);
- return;
- }
-
- bdev->rds_info.text_len = bdev->fifo_size;
-
- bcm2048_parse_rds_pi(bdev);
- bcm2048_parse_rds_rt(bdev);
- bcm2048_parse_rds_ps(bdev);
-
- mutex_unlock(&bdev->mutex);
-
- wake_up_interruptible(&bdev->read_queue);
-}
-
-static int bcm2048_get_rds_data(struct bcm2048_device *bdev, char *data)
-{
- int err = 0, i, p = 0;
- char *data_buffer;
-
- mutex_lock(&bdev->mutex);
-
- if (!bdev->rds_info.text_len) {
- err = -EINVAL;
- goto unlock;
- }
-
- data_buffer = kcalloc(BCM2048_MAX_RDS_RADIO_TEXT, 5, GFP_KERNEL);
- if (!data_buffer) {
- err = -ENOMEM;
- goto unlock;
- }
-
- for (i = 0; i < bdev->rds_info.text_len; i++) {
- p += sprintf(data_buffer + p, "%x ",
- bdev->rds_info.radio_text[i]);
- }
-
- memcpy(data, data_buffer, p);
- kfree(data_buffer);
-
-unlock:
- mutex_unlock(&bdev->mutex);
- return err;
-}
-
-/*
- * BCM2048 default initialization sequence
- */
-static int bcm2048_init(struct bcm2048_device *bdev)
-{
- int err;
-
- err = bcm2048_set_power_state(bdev, BCM2048_POWER_ON);
- if (err < 0)
- goto exit;
-
- err = bcm2048_set_audio_route(bdev, BCM2048_AUDIO_ROUTE_DAC);
- if (err < 0)
- goto exit;
-
- err = bcm2048_set_dac_output(bdev, BCM2048_DAC_OUTPUT_LEFT |
- BCM2048_DAC_OUTPUT_RIGHT);
-
-exit:
- return err;
-}
-
-/*
- * BCM2048 default deinitialization sequence
- */
-static int bcm2048_deinit(struct bcm2048_device *bdev)
-{
- int err;
-
- err = bcm2048_set_audio_route(bdev, 0);
- if (err < 0)
- return err;
-
- err = bcm2048_set_dac_output(bdev, 0);
- if (err < 0)
- return err;
-
- return bcm2048_set_power_state(bdev, BCM2048_POWER_OFF);
-}
-
-/*
- * BCM2048 probe sequence
- */
-static int bcm2048_probe(struct bcm2048_device *bdev)
-{
- int err;
-
- err = bcm2048_set_power_state(bdev, BCM2048_POWER_ON);
- if (err < 0)
- goto unlock;
-
- err = bcm2048_checkrev(bdev);
- if (err < 0)
- goto unlock;
-
- err = bcm2048_set_mute(bdev, BCM2048_DEFAULT_MUTE);
- if (err < 0)
- goto unlock;
-
- err = bcm2048_set_region(bdev, BCM2048_DEFAULT_REGION);
- if (err < 0)
- goto unlock;
-
- err = bcm2048_set_fm_search_rssi_threshold(bdev,
- BCM2048_DEFAULT_RSSI_THRESHOLD);
- if (err < 0)
- goto unlock;
-
- err = bcm2048_set_fm_automatic_stereo_mono(bdev, BCM2048_ITEM_ENABLED);
- if (err < 0)
- goto unlock;
-
- err = bcm2048_get_rds_wline(bdev);
- if (err < BCM2048_DEFAULT_RDS_WLINE)
- err = bcm2048_set_rds_wline(bdev, BCM2048_DEFAULT_RDS_WLINE);
- if (err < 0)
- goto unlock;
-
- err = bcm2048_set_power_state(bdev, BCM2048_POWER_OFF);
-
- init_waitqueue_head(&bdev->read_queue);
- bdev->rds_data_available = 0;
- bdev->rd_index = 0;
- bdev->users = 0;
-
-unlock:
- return err;
-}
-
-/*
- * BCM2048 workqueue handler
- */
-static void bcm2048_work(struct work_struct *work)
-{
- struct bcm2048_device *bdev;
- u8 flag_lsb = 0, flag_msb = 0, flags;
-
- bdev = container_of(work, struct bcm2048_device, work);
- bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG0, &flag_lsb);
- bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG1, &flag_msb);
-
- if (flag_lsb & (BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED |
- BCM2048_FM_FLAG_SEARCH_TUNE_FAIL)) {
- if (flag_lsb & BCM2048_FM_FLAG_SEARCH_TUNE_FAIL)
- bdev->scan_state = BCM2048_SCAN_FAIL;
- else
- bdev->scan_state = BCM2048_SCAN_OK;
-
- complete(&bdev->compl);
- }
-
- if (flag_msb & BCM2048_RDS_FLAG_FIFO_WLINE) {
- bcm2048_rds_fifo_receive(bdev);
- if (bdev->rds_state) {
- flags = BCM2048_RDS_FLAG_FIFO_WLINE;
- bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
- flags);
- }
- bdev->rds_data_available = 1;
- bdev->rd_index = 0; /* new data, new start */
- }
-}
-
-/*
- * BCM2048 interrupt handler
- */
-static irqreturn_t bcm2048_handler(int irq, void *dev)
-{
- struct bcm2048_device *bdev = dev;
-
- dev_dbg(&bdev->client->dev, "IRQ called, queuing work\n");
- if (bdev->power_state)
- schedule_work(&bdev->work);
-
- return IRQ_HANDLED;
-}
-
-/*
- * BCM2048 sysfs interface definitions
- */
-#define property_write(prop, type, mask, check) \
-static ssize_t bcm2048_##prop##_write(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, \
- size_t count) \
-{ \
- struct bcm2048_device *bdev = dev_get_drvdata(dev); \
- type value; \
- int err; \
- \
- if (!bdev) \
- return -ENODEV; \
- \
- if (sscanf(buf, mask, &value) != 1) \
- return -EINVAL; \
- \
- if (check) \
- return -EDOM; \
- \
- err = bcm2048_set_##prop(bdev, value); \
- \
- return err < 0 ? err : count; \
-}
-
-#define property_read(prop, mask) \
-static ssize_t bcm2048_##prop##_read(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct bcm2048_device *bdev = dev_get_drvdata(dev); \
- int value; \
- \
- if (!bdev) \
- return -ENODEV; \
- \
- value = bcm2048_get_##prop(bdev); \
- \
- if (value >= 0) \
- value = sprintf(buf, mask "\n", value); \
- \
- return value; \
-}
-
-#define property_signed_read(prop, size, mask) \
-static ssize_t bcm2048_##prop##_read(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct bcm2048_device *bdev = dev_get_drvdata(dev); \
- size value; \
- \
- if (!bdev) \
- return -ENODEV; \
- \
- value = bcm2048_get_##prop(bdev); \
- \
- return sprintf(buf, mask "\n", value); \
-}
-
-#define DEFINE_SYSFS_PROPERTY(prop, prop_type, mask, check) \
-property_write(prop, prop_type, mask, check) \
-property_read(prop, mask) \
-
-#define property_str_read(prop, size) \
-static ssize_t bcm2048_##prop##_read(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct bcm2048_device *bdev = dev_get_drvdata(dev); \
- int count; \
- u8 *out; \
- \
- if (!bdev) \
- return -ENODEV; \
- \
- out = kzalloc((size) + 1, GFP_KERNEL); \
- if (!out) \
- return -ENOMEM; \
- \
- bcm2048_get_##prop(bdev, out); \
- count = sprintf(buf, "%s\n", out); \
- \
- kfree(out); \
- \
- return count; \
-}
-
-DEFINE_SYSFS_PROPERTY(power_state, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(mute, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(audio_route, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(dac_output, unsigned int, "%u", 0)
-
-DEFINE_SYSFS_PROPERTY(fm_hi_lo_injection, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(fm_frequency, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(fm_af_frequency, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(fm_deemphasis, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(fm_rds_mask, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(fm_best_tune_mode, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(fm_search_rssi_threshold, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(fm_search_mode_direction, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(fm_search_tune_mode, unsigned int, "%u", value > 3)
-
-DEFINE_SYSFS_PROPERTY(rds, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(rds_b_block_mask, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(rds_b_block_match, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(rds_pi_mask, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(rds_pi_match, unsigned int, "%u", 0)
-DEFINE_SYSFS_PROPERTY(rds_wline, unsigned int, "%u", 0)
-property_read(rds_pi, "%x")
-property_str_read(rds_rt, (BCM2048_MAX_RDS_RT + 1))
-property_str_read(rds_ps, (BCM2048_MAX_RDS_PS + 1))
-
-property_read(fm_rds_flags, "%u")
-property_str_read(rds_data, BCM2048_MAX_RDS_RADIO_TEXT * 5)
-
-property_read(region_bottom_frequency, "%u")
-property_read(region_top_frequency, "%u")
-property_signed_read(fm_carrier_error, int, "%d")
-property_signed_read(fm_rssi, int, "%d")
-DEFINE_SYSFS_PROPERTY(region, unsigned int, "%u", 0)
-
-static struct device_attribute attrs[] = {
- __ATTR(power_state, 0644, bcm2048_power_state_read,
- bcm2048_power_state_write),
- __ATTR(mute, 0644, bcm2048_mute_read,
- bcm2048_mute_write),
- __ATTR(audio_route, 0644, bcm2048_audio_route_read,
- bcm2048_audio_route_write),
- __ATTR(dac_output, 0644, bcm2048_dac_output_read,
- bcm2048_dac_output_write),
- __ATTR(fm_hi_lo_injection, 0644,
- bcm2048_fm_hi_lo_injection_read,
- bcm2048_fm_hi_lo_injection_write),
- __ATTR(fm_frequency, 0644, bcm2048_fm_frequency_read,
- bcm2048_fm_frequency_write),
- __ATTR(fm_af_frequency, 0644,
- bcm2048_fm_af_frequency_read,
- bcm2048_fm_af_frequency_write),
- __ATTR(fm_deemphasis, 0644, bcm2048_fm_deemphasis_read,
- bcm2048_fm_deemphasis_write),
- __ATTR(fm_rds_mask, 0644, bcm2048_fm_rds_mask_read,
- bcm2048_fm_rds_mask_write),
- __ATTR(fm_best_tune_mode, 0644,
- bcm2048_fm_best_tune_mode_read,
- bcm2048_fm_best_tune_mode_write),
- __ATTR(fm_search_rssi_threshold, 0644,
- bcm2048_fm_search_rssi_threshold_read,
- bcm2048_fm_search_rssi_threshold_write),
- __ATTR(fm_search_mode_direction, 0644,
- bcm2048_fm_search_mode_direction_read,
- bcm2048_fm_search_mode_direction_write),
- __ATTR(fm_search_tune_mode, 0644,
- bcm2048_fm_search_tune_mode_read,
- bcm2048_fm_search_tune_mode_write),
- __ATTR(rds, 0644, bcm2048_rds_read,
- bcm2048_rds_write),
- __ATTR(rds_b_block_mask, 0644,
- bcm2048_rds_b_block_mask_read,
- bcm2048_rds_b_block_mask_write),
- __ATTR(rds_b_block_match, 0644,
- bcm2048_rds_b_block_match_read,
- bcm2048_rds_b_block_match_write),
- __ATTR(rds_pi_mask, 0644, bcm2048_rds_pi_mask_read,
- bcm2048_rds_pi_mask_write),
- __ATTR(rds_pi_match, 0644, bcm2048_rds_pi_match_read,
- bcm2048_rds_pi_match_write),
- __ATTR(rds_wline, 0644, bcm2048_rds_wline_read,
- bcm2048_rds_wline_write),
- __ATTR(rds_pi, 0444, bcm2048_rds_pi_read, NULL),
- __ATTR(rds_rt, 0444, bcm2048_rds_rt_read, NULL),
- __ATTR(rds_ps, 0444, bcm2048_rds_ps_read, NULL),
- __ATTR(fm_rds_flags, 0444, bcm2048_fm_rds_flags_read, NULL),
- __ATTR(region_bottom_frequency, 0444,
- bcm2048_region_bottom_frequency_read, NULL),
- __ATTR(region_top_frequency, 0444,
- bcm2048_region_top_frequency_read, NULL),
- __ATTR(fm_carrier_error, 0444,
- bcm2048_fm_carrier_error_read, NULL),
- __ATTR(fm_rssi, 0444,
- bcm2048_fm_rssi_read, NULL),
- __ATTR(region, 0644, bcm2048_region_read,
- bcm2048_region_write),
- __ATTR(rds_data, 0444, bcm2048_rds_data_read, NULL),
-};
-
-static int bcm2048_sysfs_unregister_properties(struct bcm2048_device *bdev,
- int size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- device_remove_file(&bdev->client->dev, &attrs[i]);
-
- return 0;
-}
-
-static int bcm2048_sysfs_register_properties(struct bcm2048_device *bdev)
-{
- int err = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(attrs); i++) {
- if (device_create_file(&bdev->client->dev, &attrs[i]) != 0) {
- dev_err(&bdev->client->dev,
- "could not register sysfs entry\n");
- err = -EBUSY;
- bcm2048_sysfs_unregister_properties(bdev, i);
- break;
- }
- }
-
- return err;
-}
-
-static int bcm2048_fops_open(struct file *file)
-{
- struct bcm2048_device *bdev = video_drvdata(file);
-
- bdev->users++;
- bdev->rd_index = 0;
- bdev->rds_data_available = 0;
-
- return 0;
-}
-
-static int bcm2048_fops_release(struct file *file)
-{
- struct bcm2048_device *bdev = video_drvdata(file);
-
- bdev->users--;
-
- return 0;
-}
-
-static __poll_t bcm2048_fops_poll(struct file *file,
- struct poll_table_struct *pts)
-{
- struct bcm2048_device *bdev = video_drvdata(file);
- __poll_t retval = 0;
-
- poll_wait(file, &bdev->read_queue, pts);
-
- if (bdev->rds_data_available)
- retval = EPOLLIN | EPOLLRDNORM;
-
- return retval;
-}
-
-static ssize_t bcm2048_fops_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct bcm2048_device *bdev = video_drvdata(file);
- int i;
- int retval = 0;
-
- /* we return at least 3 bytes, one block */
- count = (count / 3) * 3; /* only multiples of 3 */
- if (count < 3)
- return -ENOBUFS;
-
- while (!bdev->rds_data_available) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EWOULDBLOCK;
- goto done;
- }
- /* interruptible_sleep_on(&bdev->read_queue); */
- if (wait_event_interruptible(bdev->read_queue,
- bdev->rds_data_available) < 0) {
- retval = -EINTR;
- goto done;
- }
- }
-
- mutex_lock(&bdev->mutex);
- /* copy data to userspace */
- i = bdev->fifo_size - bdev->rd_index;
- if (count > i)
- count = (i / 3) * 3;
-
- i = 0;
- while (i < count) {
- unsigned char tmpbuf[3];
-
- tmpbuf[i] = bdev->rds_info.radio_text[bdev->rd_index + i + 2];
- tmpbuf[i + 1] =
- bdev->rds_info.radio_text[bdev->rd_index + i + 1];
- tmpbuf[i + 2] =
- (bdev->rds_info.radio_text[bdev->rd_index + i] &
- 0xf0) >> 4;
- if ((bdev->rds_info.radio_text[bdev->rd_index + i] &
- BCM2048_RDS_CRC_MASK) == BCM2048_RDS_CRC_UNRECOVARABLE)
- tmpbuf[i + 2] |= 0x80;
- if (copy_to_user(buf + i, tmpbuf, 3)) {
- retval = -EFAULT;
- break;
- }
- i += 3;
- }
-
- bdev->rd_index += i;
- if (bdev->rd_index >= bdev->fifo_size)
- bdev->rds_data_available = 0;
-
- mutex_unlock(&bdev->mutex);
- if (retval == 0)
- retval = i;
-
-done:
- return retval;
-}
-
-/*
- * bcm2048_fops - file operations interface
- */
-static const struct v4l2_file_operations bcm2048_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
- /* for RDS read support */
- .open = bcm2048_fops_open,
- .release = bcm2048_fops_release,
- .read = bcm2048_fops_read,
- .poll = bcm2048_fops_poll
-};
-
-/*
- * Video4Linux Interface
- */
-static struct v4l2_queryctrl bcm2048_v4l2_queryctrl[] = {
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_AUDIO_BALANCE,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_AUDIO_BASS,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_AUDIO_TREBLE,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_AUDIO_LOUDNESS,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
-};
-
-static int bcm2048_vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *capability)
-{
- struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
-
- strscpy(capability->driver, BCM2048_DRIVER_NAME,
- sizeof(capability->driver));
- strscpy(capability->card, BCM2048_DRIVER_CARD,
- sizeof(capability->card));
- snprintf(capability->bus_info, 32, "I2C: 0x%X", bdev->client->addr);
- return 0;
-}
-
-static int bcm2048_vidioc_g_input(struct file *filp, void *priv,
- unsigned int *i)
-{
- *i = 0;
-
- return 0;
-}
-
-static int bcm2048_vidioc_s_input(struct file *filp, void *priv,
- unsigned int i)
-{
- if (i)
- return -EINVAL;
-
- return 0;
-}
-
-static int bcm2048_vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bcm2048_v4l2_queryctrl); i++) {
- if (qc->id && qc->id == bcm2048_v4l2_queryctrl[i].id) {
- *qc = bcm2048_v4l2_queryctrl[i];
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-static int bcm2048_vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
- int err = 0;
-
- if (!bdev)
- return -ENODEV;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- err = bcm2048_get_mute(bdev);
- if (err >= 0)
- ctrl->value = err;
- break;
- }
-
- return err;
-}
-
-static int bcm2048_vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
- int err = 0;
-
- if (!bdev)
- return -ENODEV;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value) {
- if (bdev->power_state) {
- err = bcm2048_set_mute(bdev, ctrl->value);
- err |= bcm2048_deinit(bdev);
- }
- } else {
- if (!bdev->power_state) {
- err = bcm2048_init(bdev);
- err |= bcm2048_set_mute(bdev, ctrl->value);
- }
- }
- break;
- }
-
- return err;
-}
-
-static int bcm2048_vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *audio)
-{
- if (audio->index > 1)
- return -EINVAL;
-
- strscpy(audio->name, "Radio", sizeof(audio->name));
- audio->capability = V4L2_AUDCAP_STEREO;
-
- return 0;
-}
-
-static int bcm2048_vidioc_s_audio(struct file *file, void *priv,
- const struct v4l2_audio *audio)
-{
- if (audio->index != 0)
- return -EINVAL;
-
- return 0;
-}
-
-static int bcm2048_vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *tuner)
-{
- struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
- s8 f_error;
- s8 rssi;
-
- if (!bdev)
- return -ENODEV;
-
- if (tuner->index > 0)
- return -EINVAL;
-
- strscpy(tuner->name, "FM Receiver", sizeof(tuner->name));
- tuner->type = V4L2_TUNER_RADIO;
- tuner->rangelow =
- dev_to_v4l2(bcm2048_get_region_bottom_frequency(bdev));
- tuner->rangehigh =
- dev_to_v4l2(bcm2048_get_region_top_frequency(bdev));
- tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
- tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
- tuner->audmode = V4L2_TUNER_MODE_STEREO;
- tuner->afc = 0;
- if (bdev->power_state) {
- /*
- * Report frequencies with high carrier errors to have zero
- * signal level
- */
- f_error = bcm2048_get_fm_carrier_error(bdev);
- if (f_error < BCM2048_FREQ_ERROR_FLOOR ||
- f_error > BCM2048_FREQ_ERROR_ROOF) {
- tuner->signal = 0;
- } else {
- /*
- * RSSI level -60 dB is defined to report full
- * signal strength
- */
- rssi = bcm2048_get_fm_rssi(bdev);
- if (rssi >= BCM2048_RSSI_LEVEL_BASE) {
- tuner->signal = 0xFFFF;
- } else if (rssi > BCM2048_RSSI_LEVEL_ROOF) {
- tuner->signal = (rssi +
- BCM2048_RSSI_LEVEL_ROOF_NEG)
- * BCM2048_SIGNAL_MULTIPLIER;
- } else {
- tuner->signal = 0;
- }
- }
- } else {
- tuner->signal = 0;
- }
-
- return 0;
-}
-
-static int bcm2048_vidioc_s_tuner(struct file *file, void *priv,
- const struct v4l2_tuner *tuner)
-{
- struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
-
- if (!bdev)
- return -ENODEV;
-
- if (tuner->index > 0)
- return -EINVAL;
-
- return 0;
-}
-
-static int bcm2048_vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
-{
- struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
- int err = 0;
- int f;
-
- if (!bdev->power_state)
- return -ENODEV;
-
- freq->type = V4L2_TUNER_RADIO;
- f = bcm2048_get_fm_frequency(bdev);
-
- if (f < 0)
- err = f;
- else
- freq->frequency = dev_to_v4l2(f);
-
- return err;
-}
-
-static int bcm2048_vidioc_s_frequency(struct file *file, void *priv,
- const struct v4l2_frequency *freq)
-{
- struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
- int err;
-
- if (freq->type != V4L2_TUNER_RADIO)
- return -EINVAL;
-
- if (!bdev->power_state)
- return -ENODEV;
-
- err = bcm2048_set_fm_frequency(bdev, v4l2_to_dev(freq->frequency));
- err |= bcm2048_set_fm_search_tune_mode(bdev, BCM2048_FM_PRE_SET_MODE);
-
- return err;
-}
-
-static int bcm2048_vidioc_s_hw_freq_seek(struct file *file, void *priv,
- const struct v4l2_hw_freq_seek *seek)
-{
- struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
- int err;
-
- if (!bdev->power_state)
- return -ENODEV;
-
- if ((seek->tuner != 0) || (seek->type != V4L2_TUNER_RADIO))
- return -EINVAL;
-
- err = bcm2048_set_fm_search_mode_direction(bdev, seek->seek_upward);
- err |= bcm2048_set_fm_search_tune_mode(bdev,
- BCM2048_FM_AUTO_SEARCH_MODE);
-
- return err;
-}
-
-static const struct v4l2_ioctl_ops bcm2048_ioctl_ops = {
- .vidioc_querycap = bcm2048_vidioc_querycap,
- .vidioc_g_input = bcm2048_vidioc_g_input,
- .vidioc_s_input = bcm2048_vidioc_s_input,
- .vidioc_queryctrl = bcm2048_vidioc_queryctrl,
- .vidioc_g_ctrl = bcm2048_vidioc_g_ctrl,
- .vidioc_s_ctrl = bcm2048_vidioc_s_ctrl,
- .vidioc_g_audio = bcm2048_vidioc_g_audio,
- .vidioc_s_audio = bcm2048_vidioc_s_audio,
- .vidioc_g_tuner = bcm2048_vidioc_g_tuner,
- .vidioc_s_tuner = bcm2048_vidioc_s_tuner,
- .vidioc_g_frequency = bcm2048_vidioc_g_frequency,
- .vidioc_s_frequency = bcm2048_vidioc_s_frequency,
- .vidioc_s_hw_freq_seek = bcm2048_vidioc_s_hw_freq_seek,
-};
-
-/*
- * bcm2048_viddev_template - video device interface
- */
-static const struct video_device bcm2048_viddev_template = {
- .fops = &bcm2048_fops,
- .name = BCM2048_DRIVER_NAME,
- .release = video_device_release_empty,
- .ioctl_ops = &bcm2048_ioctl_ops,
- .device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
- V4L2_CAP_HW_FREQ_SEEK,
-};
-
-/*
- * I2C driver interface
- */
-static int bcm2048_i2c_driver_probe(struct i2c_client *client)
-{
- struct bcm2048_device *bdev;
- int err;
-
- bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
- if (!bdev) {
- err = -ENOMEM;
- goto exit;
- }
-
- bdev->client = client;
- i2c_set_clientdata(client, bdev);
- mutex_init(&bdev->mutex);
- init_completion(&bdev->compl);
- INIT_WORK(&bdev->work, bcm2048_work);
-
- if (client->irq) {
- err = request_irq(client->irq,
- bcm2048_handler, IRQF_TRIGGER_FALLING,
- client->name, bdev);
- if (err < 0) {
- dev_err(&client->dev, "Could not request IRQ\n");
- goto free_bdev;
- }
- dev_dbg(&client->dev, "IRQ requested.\n");
- } else {
- dev_dbg(&client->dev, "IRQ not configured. Using timeouts.\n");
- }
-
- bdev->videodev = bcm2048_viddev_template;
- video_set_drvdata(&bdev->videodev, bdev);
- if (video_register_device(&bdev->videodev, VFL_TYPE_RADIO, radio_nr)) {
- dev_dbg(&client->dev, "Could not register video device.\n");
- err = -EIO;
- goto free_irq;
- }
-
- err = bcm2048_sysfs_register_properties(bdev);
- if (err < 0) {
- dev_dbg(&client->dev, "Could not register sysfs interface.\n");
- goto free_registration;
- }
-
- err = bcm2048_probe(bdev);
- if (err < 0) {
- dev_dbg(&client->dev, "Failed to probe device information.\n");
- goto free_sysfs;
- }
-
- return 0;
-
-free_sysfs:
- bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs));
-free_registration:
- video_unregister_device(&bdev->videodev);
-free_irq:
- if (client->irq)
- free_irq(client->irq, bdev);
-free_bdev:
- i2c_set_clientdata(client, NULL);
- kfree(bdev);
-exit:
- return err;
-}
-
-static int bcm2048_i2c_driver_remove(struct i2c_client *client)
-{
- struct bcm2048_device *bdev = i2c_get_clientdata(client);
-
- if (!client->adapter)
- return -ENODEV;
-
- if (bdev) {
- bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs));
- video_unregister_device(&bdev->videodev);
-
- if (bdev->power_state)
- bcm2048_set_power_state(bdev, BCM2048_POWER_OFF);
-
- if (client->irq > 0)
- free_irq(client->irq, bdev);
-
- cancel_work_sync(&bdev->work);
-
- kfree(bdev);
- }
-
- return 0;
-}
-
-/*
- * bcm2048_i2c_driver - i2c driver interface
- */
-static const struct i2c_device_id bcm2048_id[] = {
- { "bcm2048", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, bcm2048_id);
-
-static struct i2c_driver bcm2048_i2c_driver = {
- .driver = {
- .name = BCM2048_DRIVER_NAME,
- },
- .probe_new = bcm2048_i2c_driver_probe,
- .remove = bcm2048_i2c_driver_remove,
- .id_table = bcm2048_id,
-};
-
-module_i2c_driver(bcm2048_i2c_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR(BCM2048_DRIVER_AUTHOR);
-MODULE_DESCRIPTION(BCM2048_DRIVER_DESC);
-MODULE_VERSION("0.0.2");
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.h b/drivers/staging/media/bcm2048/radio-bcm2048.h
deleted file mode 100644
index 22887a075257..000000000000
--- a/drivers/staging/media/bcm2048/radio-bcm2048.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * drivers/staging/media/radio-bcm2048.h
- *
- * Property and command definitions for bcm2048 radio receiver chip.
- *
- * Copyright (C) Nokia Corporation
- * Contact: Eero Nurkkala <ext-eero.nurkkala@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#ifndef BCM2048_H
-#define BCM2048_H
-
-#define BCM2048_NAME "bcm2048"
-#define BCM2048_I2C_ADDR 0x22
-
-#endif /* ifndef BCM2048_H */
diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig
deleted file mode 100644
index 94bf6746c03f..000000000000
--- a/drivers/staging/media/davinci_vpfe/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-config VIDEO_DM365_VPFE
- tristate "DM365 VPFE Media Controller Capture Driver"
- depends on VIDEO_V4L2
- depends on (ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF) || (COMPILE_TEST && !ARCH_OMAP1)
- depends on VIDEO_V4L2_SUBDEV_API
- depends on VIDEO_DAVINCI_VPBE_DISPLAY
- select VIDEOBUF2_DMA_CONTIG
- help
- Support for DM365 VPFE based Media Controller Capture driver.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe-mc-capture.
diff --git a/drivers/staging/media/davinci_vpfe/Makefile b/drivers/staging/media/davinci_vpfe/Makefile
deleted file mode 100644
index 0ae8c5014f74..000000000000
--- a/drivers/staging/media/davinci_vpfe/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci-vfpe.o
-
-davinci-vfpe-objs := \
- dm365_isif.o dm365_ipipe_hw.o dm365_ipipe.o \
- dm365_resizer.o dm365_ipipeif.o vpfe_mc_capture.o vpfe_video.o
-
-# Allow building it with COMPILE_TEST on other archs
-ifndef CONFIG_ARCH_DAVINCI
-ccflags-y += -I $(srctree)/arch/arm/mach-davinci/include/
-endif
diff --git a/drivers/staging/media/davinci_vpfe/TODO b/drivers/staging/media/davinci_vpfe/TODO
deleted file mode 100644
index cc8bd9306f2a..000000000000
--- a/drivers/staging/media/davinci_vpfe/TODO
+++ /dev/null
@@ -1,38 +0,0 @@
-TODO (general):
-==================================
-
-- User space interface refinement
- - Controls should be used when possible rather than private ioctl
- - No enums should be used
- - Use of MC and V4L2 subdev APIs when applicable
- - Single interface header might suffice
- - Current interface forces to configure everything at once
-- Get rid of the dm365_ipipe_hw.[ch] layer
-- Active external sub-devices defined by link configuration; no strcmp
- needed
-- More generic platform data (i2c adapters)
-- The driver should have no knowledge of possible external subdevs; see
- struct vpfe_subdev_id
-- Some of the hardware control should be refactorede
-- Check proper serialisation (through mutexes and spinlocks)
-- Names that are visible in kernel global namespace should have a common
- prefix (or a few)
-- While replacing the older driver in media folder, provide a compatibility
- layer and compatibility tests that warrants (using the libv4l's LD_PRELOAD
- approach) there is no regression for the users using the older driver.
-- make it independent of arch-specific APIs (mach/mux.h).
-
-Building of uImage and Applications:
-==================================
-
-As of now since the interface will undergo few changes all the include
-files are present in staging itself, to build for dm365 follow below steps,
-
-- copy vpfe.h from drivers/staging/media/davinci_vpfe/ to
- include/media/davinci/ folder for building the uImage.
-- copy davinci_vpfe_user.h from drivers/staging/media/davinci_vpfe/ to
- include/uapi/linux/davinci_vpfe.h, and add a entry in Kbuild (required
- for building application).
-- copy dm365_ipipeif_user.h from drivers/staging/media/davinci_vpfe/ to
- include/uapi/linux/dm365_ipipeif.h and a entry in Kbuild (required
- for building application).
diff --git a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt b/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt
deleted file mode 100644
index a1e91778aa9b..000000000000
--- a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt
+++ /dev/null
@@ -1,154 +0,0 @@
-Davinci Video processing Front End (VPFE) driver
-
-Copyright (C) 2012 Texas Instruments Inc
-
-Contacts: Manjunath Hadli <manjunath.hadli@ti.com>
- Prabhakar Lad <prabhakar.lad@ti.com>
-
-
-Introduction
-============
-
-This file documents the Texas Instruments Davinci Video processing Front End
-(VPFE) driver located under drivers/media/platform/davinci. The original driver
-exists for Davinci VPFE, which is now being changed to Media Controller
-Framework.
-
-Currently the driver has been successfully used on the following
-version of Davinci:
-
- DM365/DM368
-
-The driver implements V4L2, Media controller and v4l2_subdev interfaces. Sensor,
-lens and flash drivers using the v4l2_subdev interface in the kernel are
-supported.
-
-
-Split to subdevs
-================
-
-The Davinci VPFE is split into V4L2 subdevs, each of the blocks inside the VPFE
-having one subdev to represent it. Each of the subdevs provide a V4L2 subdev
-interface to userspace.
-
- DAVINCI ISIF
- DAVINCI IPIPEIF
- DAVINCI IPIPE
- DAVINCI CROP RESIZER
- DAVINCI RESIZER A
- DAVINCI RESIZER B
-
-Each possible link in the VPFE is modelled by a link in the Media controller
-interface. For an example program see [1].
-
-
-ISIF, IPIPE, and RESIZER block IOCTLs
-======================================
-
-The Davinci Video processing Front End (VPFE) driver supports standard V4L2
-IOCTLs and controls where possible and practical. Much of the functions provided
-by the VPFE, however, does not fall under the standard IOCTL's.
-
-In general, there is a private ioctl for configuring each of the blocks
-containing hardware-dependent functions.
-
-The following private IOCTLs are supported:
-
- VIDIOC_VPFE_ISIF_[S/G]_RAW_PARAMS
- VIDIOC_VPFE_IPIPE_[S/G]_CONFIG
- VIDIOC_VPFE_RSZ_[S/G]_CONFIG
-
-The parameter structures used by these ioctl's are described in
-include/uapi/linux/davinci_vpfe.h.
-
-The VIDIOC_VPFE_ISIF_S_RAW_PARAMS, VIDIOC_VPFE_IPIPE_S_CONFIG and
-VIDIOC_VPFE_RSZ_S_CONFIG are used to configure, enable and disable functions in
-the isif, ipipe and resizer blocks respectively. These IOCTL's control several
-functions in the blocks they control. VIDIOC_VPFE_ISIF_S_RAW_PARAMS IOCTL
-accepts a pointer to struct vpfe_isif_raw_config as its argument. Similarly
-VIDIOC_VPFE_IPIPE_S_CONFIG accepts a pointer to struct vpfe_ipipe_config. And
-VIDIOC_VPFE_RSZ_S_CONFIG accepts a pointer to struct vpfe_rsz_config as its
-argument. Similarly VIDIOC_VPFE_ISIF_G_RAW_PARAMS, VIDIOC_VPFE_IPIPE_G_CONFIG
-and VIDIOC_VPFE_RSZ_G_CONFIG are used to get the current configuration set in
-the isif, ipipe and resizer blocks respectively.
-
-The detailed functions of the VPFE itself related to a given VPFE block is
-described in the Technical Reference Manuals (TRMs) --- see the end of the
-document for those.
-
-
-IPIPEIF block IOCTLs
-======================================
-
-The following private IOCTLs are supported:
-
- VIDIOC_VPFE_IPIPEIF_[S/G]_CONFIG
-
-The parameter structures used by these ioctl's are described in
-include/uapi/linux/dm365_ipipeif.h
-
-The VIDIOC_VPFE_IPIPEIF_S_CONFIG is used to configure the ipipeif
-hardware block. The VIDIOC_VPFE_IPIPEIF_S_CONFIG and
-VIDIOC_VPFE_IPIPEIF_G_CONFIG accepts a pointer to struct ipipeif_params
-as its argument.
-
-
-VPFE Operating Modes
-==========================================
-
-a: Continuous Modes
-------------------------
-
-1: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> SDRAM
-
-2: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> DAVINCI IPIPEIF--->|
- |
- <--------------------<----------------<---------------------<---|
- |
- V
- DAVINCI CROP RESIZER--->DAVINCI RESIZER [A/B]---> SDRAM
-
-3: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> DAVINCI IPIPEIF--->|
- |
- <--------------------<----------------<---------------------<---|
- |
- V
- DAVINCI IPIPE---> DAVINCI CROP RESIZER--->DAVINCI RESIZER [A/B]---> SDRAM
-
-a: Single Shot Modes
-------------------------
-
-1: SDRAM---> DAVINCI IPIPEIF---> DAVINCI IPIPE---> DAVINCI CROP RESIZER--->|
- |
- <----------------<----------------<------------------<---------------<--|
- |
- V
-DAVINCI RESIZER [A/B]---> SDRAM
-
-2: SDRAM---> DAVINCI IPIPEIF---> DAVINCI CROP RESIZER--->|
- |
- <----------------<----------------<---------------<---|
- |
- V
-DAVINCI RESIZER [A/B]---> SDRAM
-
-
-Technical reference manuals (TRMs) and other documentation
-==========================================================
-
-Davinci DM365 TRM:
-<URL:http://www.ti.com/lit/ds/sprs457e/sprs457e.pdf>
-Referenced MARCH 2009-REVISED JUNE 2011
-
-Davinci DM368 TRM:
-<URL:http://www.ti.com/lit/ds/sprs668c/sprs668c.pdf>
-Referenced APRIL 2010-REVISED JUNE 2011
-
-Davinci Video Processing Front End (VPFE) DM36x
-<URL:http://www.ti.com/lit/ug/sprufg8c/sprufg8c.pdf>
-
-
-References
-==========
-
-[1] http://git.ideasonboard.org/?p=media-ctl.git;a=summary
diff --git a/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h b/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h
deleted file mode 100644
index 8d772029c91d..000000000000
--- a/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h
+++ /dev/null
@@ -1,1287 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_USER_H
-#define _DAVINCI_VPFE_USER_H
-
-#include <linux/types.h>
-#include <linux/videodev2.h>
-
-/*
- * Private IOCTL
- *
- * VIDIOC_VPFE_ISIF_S_RAW_PARAMS: Set raw params in isif
- * VIDIOC_VPFE_ISIF_G_RAW_PARAMS: Get raw params from isif
- * VIDIOC_VPFE_PRV_S_CONFIG: Set ipipe engine configuration
- * VIDIOC_VPFE_PRV_G_CONFIG: Get ipipe engine configuration
- * VIDIOC_VPFE_RSZ_S_CONFIG: Set resizer engine configuration
- * VIDIOC_VPFE_RSZ_G_CONFIG: Get resizer engine configuration
- */
-
-#define VIDIOC_VPFE_ISIF_S_RAW_PARAMS \
- _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct vpfe_isif_raw_config)
-#define VIDIOC_VPFE_ISIF_G_RAW_PARAMS \
- _IOR('V', BASE_VIDIOC_PRIVATE + 2, struct vpfe_isif_raw_config)
-#define VIDIOC_VPFE_IPIPE_S_CONFIG \
- _IOWR('P', BASE_VIDIOC_PRIVATE + 3, struct vpfe_ipipe_config)
-#define VIDIOC_VPFE_IPIPE_G_CONFIG \
- _IOWR('P', BASE_VIDIOC_PRIVATE + 4, struct vpfe_ipipe_config)
-#define VIDIOC_VPFE_RSZ_S_CONFIG \
- _IOWR('R', BASE_VIDIOC_PRIVATE + 5, struct vpfe_rsz_config)
-#define VIDIOC_VPFE_RSZ_G_CONFIG \
- _IOWR('R', BASE_VIDIOC_PRIVATE + 6, struct vpfe_rsz_config)
-
-/*
- * Private Control's for ISIF
- */
-#define VPFE_ISIF_CID_CRGAIN (V4L2_CID_USER_BASE | 0xa001)
-#define VPFE_ISIF_CID_CGRGAIN (V4L2_CID_USER_BASE | 0xa002)
-#define VPFE_ISIF_CID_CGBGAIN (V4L2_CID_USER_BASE | 0xa003)
-#define VPFE_ISIF_CID_CBGAIN (V4L2_CID_USER_BASE | 0xa004)
-#define VPFE_ISIF_CID_GAIN_OFFSET (V4L2_CID_USER_BASE | 0xa005)
-
-/*
- * Private Control's for ISIF and IPIPEIF
- */
-#define VPFE_CID_DPCM_PREDICTOR (V4L2_CID_USER_BASE | 0xa006)
-
-/************************************************************************
- * Vertical Defect Correction parameters
- ***********************************************************************/
-
-/**
- * vertical defect correction methods
- */
-enum vpfe_isif_vdfc_corr_mode {
- /* Defect level subtraction. Just fed through if saturating */
- VPFE_ISIF_VDFC_NORMAL,
- /**
- * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2
- * if data saturating
- */
- VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT,
- /* Horizontal interpolation (((i-2)+(i+2))/2) */
- VPFE_ISIF_VDFC_HORZ_INTERPOL
-};
-
-/**
- * Max Size of the Vertical Defect Correction table
- */
-#define VPFE_ISIF_VDFC_TABLE_SIZE 8
-
-/**
- * Values used for shifting up the vdfc defect level
- */
-enum vpfe_isif_vdfc_shift {
- /* No Shift */
- VPFE_ISIF_VDFC_NO_SHIFT,
- /* Shift by 1 bit */
- VPFE_ISIF_VDFC_SHIFT_1,
- /* Shift by 2 bit */
- VPFE_ISIF_VDFC_SHIFT_2,
- /* Shift by 3 bit */
- VPFE_ISIF_VDFC_SHIFT_3,
- /* Shift by 4 bit */
- VPFE_ISIF_VDFC_SHIFT_4
-};
-
-/**
- * Defect Correction (DFC) table entry
- */
-struct vpfe_isif_vdfc_entry {
- /* vertical position of defect */
- unsigned short pos_vert;
- /* horizontal position of defect */
- unsigned short pos_horz;
- /**
- * Defect level of Vertical line defect position. This is subtracted
- * from the data at the defect position
- */
- unsigned char level_at_pos;
- /**
- * Defect level of the pixels upper than the vertical line defect.
- * This is subtracted from the data
- */
- unsigned char level_up_pixels;
- /**
- * Defect level of the pixels lower than the vertical line defect.
- * This is subtracted from the data
- */
- unsigned char level_low_pixels;
-};
-
-/**
- * Structure for Defect Correction (DFC) parameter
- */
-struct vpfe_isif_dfc {
- /* enable vertical defect correction */
- unsigned char en;
- /* Correction methods */
- enum vpfe_isif_vdfc_corr_mode corr_mode;
- /**
- * 0 - whole line corrected, 1 - not
- * pixels upper than the defect
- */
- unsigned char corr_whole_line;
- /**
- * defect level shift value. level_at_pos, level_upper_pos,
- * and level_lower_pos can be shifted up by this value
- */
- enum vpfe_isif_vdfc_shift def_level_shift;
- /* defect saturation level */
- unsigned short def_sat_level;
- /* number of vertical defects. Max is VPFE_ISIF_VDFC_TABLE_SIZE */
- short num_vdefects;
- /* VDFC table ptr */
- struct vpfe_isif_vdfc_entry table[VPFE_ISIF_VDFC_TABLE_SIZE];
-};
-
-/************************************************************************
- * Digital/Black clamp or DC Subtract parameters
- ************************************************************************/
-/**
- * Horizontal Black Clamp modes
- */
-enum vpfe_isif_horz_bc_mode {
- /**
- * Horizontal clamp disabled. Only vertical clamp
- * value is subtracted
- */
- VPFE_ISIF_HORZ_BC_DISABLE,
- /**
- * Horizontal clamp value is calculated and subtracted
- * from image data along with vertical clamp value
- */
- VPFE_ISIF_HORZ_BC_CLAMP_CALC_ENABLED,
- /**
- * Horizontal clamp value calculated from previous image
- * is subtracted from image data along with vertical clamp
- * value. How the horizontal clamp value for the first image
- * is calculated in this case ???
- */
- VPFE_ISIF_HORZ_BC_CLAMP_NOT_UPDATED
-};
-
-/**
- * Base window selection for Horizontal Black Clamp calculations
- */
-enum vpfe_isif_horz_bc_base_win_sel {
- /* Select Most left window for bc calculation */
- VPFE_ISIF_SEL_MOST_LEFT_WIN,
-
- /* Select Most right window for bc calculation */
- VPFE_ISIF_SEL_MOST_RIGHT_WIN,
-};
-
-/* Size of window in horizontal direction for horizontal bc */
-enum vpfe_isif_horz_bc_sz_h {
- VPFE_ISIF_HORZ_BC_SZ_H_2PIXELS,
- VPFE_ISIF_HORZ_BC_SZ_H_4PIXELS,
- VPFE_ISIF_HORZ_BC_SZ_H_8PIXELS,
- VPFE_ISIF_HORZ_BC_SZ_H_16PIXELS
-};
-
-/* Size of window in vertcal direction for vertical bc */
-enum vpfe_isif_horz_bc_sz_v {
- VPFE_ISIF_HORZ_BC_SZ_H_32PIXELS,
- VPFE_ISIF_HORZ_BC_SZ_H_64PIXELS,
- VPFE_ISIF_HORZ_BC_SZ_H_128PIXELS,
- VPFE_ISIF_HORZ_BC_SZ_H_256PIXELS
-};
-
-/**
- * Structure for Horizontal Black Clamp config params
- */
-struct vpfe_isif_horz_bclamp {
- /* horizontal clamp mode */
- enum vpfe_isif_horz_bc_mode mode;
- /**
- * pixel value limit enable.
- * 0 - limit disabled
- * 1 - pixel value limited to 1023
- */
- unsigned char clamp_pix_limit;
- /**
- * Select most left or right window for clamp val
- * calculation
- */
- enum vpfe_isif_horz_bc_base_win_sel base_win_sel_calc;
- /* Window count per color for calculation. range 1-32 */
- unsigned char win_count_calc;
- /* Window start position - horizontal for calculation. 0 - 8191 */
- unsigned short win_start_h_calc;
- /* Window start position - vertical for calculation 0 - 8191 */
- unsigned short win_start_v_calc;
- /* Width of the sample window in pixels for calculation */
- enum vpfe_isif_horz_bc_sz_h win_h_sz_calc;
- /* Height of the sample window in pixels for calculation */
- enum vpfe_isif_horz_bc_sz_v win_v_sz_calc;
-};
-
-/**
- * Black Clamp vertical reset values
- */
-enum vpfe_isif_vert_bc_reset_val_sel {
- /* Reset value used is the clamp value calculated */
- VPFE_ISIF_VERT_BC_USE_HORZ_CLAMP_VAL,
- /* Reset value used is reset_clamp_val configured */
- VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL,
- /* No update, previous image value is used */
- VPFE_ISIF_VERT_BC_NO_UPDATE
-};
-
-enum vpfe_isif_vert_bc_sz_h {
- VPFE_ISIF_VERT_BC_SZ_H_2PIXELS,
- VPFE_ISIF_VERT_BC_SZ_H_4PIXELS,
- VPFE_ISIF_VERT_BC_SZ_H_8PIXELS,
- VPFE_ISIF_VERT_BC_SZ_H_16PIXELS,
- VPFE_ISIF_VERT_BC_SZ_H_32PIXELS,
- VPFE_ISIF_VERT_BC_SZ_H_64PIXELS
-};
-
-/**
- * Structure for Vertical Black Clamp configuration params
- */
-struct vpfe_isif_vert_bclamp {
- /* Reset value selection for vertical clamp calculation */
- enum vpfe_isif_vert_bc_reset_val_sel reset_val_sel;
- /* U12 value if reset_sel = ISIF_BC_VERT_USE_CONFIG_CLAMP_VAL */
- unsigned short reset_clamp_val;
- /**
- * U8Q8. Line average coefficient used in vertical clamp
- * calculation
- */
- unsigned char line_ave_coef;
- /* Width in pixels of the optical black region used for calculation. */
- enum vpfe_isif_vert_bc_sz_h ob_h_sz_calc;
- /* Height of the optical black region for calculation */
- unsigned short ob_v_sz_calc;
- /* Optical black region start position - horizontal. 0 - 8191 */
- unsigned short ob_start_h;
- /* Optical black region start position - vertical 0 - 8191 */
- unsigned short ob_start_v;
-};
-
-/**
- * Structure for Black Clamp configuration params
- */
-struct vpfe_isif_black_clamp {
- /**
- * this offset value is added irrespective of the clamp
- * enable status. S13
- */
- unsigned short dc_offset;
- /**
- * Enable black/digital clamp value to be subtracted
- * from the image data
- */
- unsigned char en;
- /**
- * black clamp mode. same/separate clamp for 4 colors
- * 0 - disable - same clamp value for all colors
- * 1 - clamp value calculated separately for all colors
- */
- unsigned char bc_mode_color;
- /* Vertical start position for bc subtraction */
- unsigned short vert_start_sub;
- /* Black clamp for horizontal direction */
- struct vpfe_isif_horz_bclamp horz;
- /* Black clamp for vertical direction */
- struct vpfe_isif_vert_bclamp vert;
-};
-
-/*************************************************************************
- ** Color Space Conversion (CSC)
- *************************************************************************/
-/**
- * Number of Coefficient values used for CSC
- */
-#define VPFE_ISIF_CSC_NUM_COEFF 16
-
-struct float_8_bit {
- /* 8 bit integer part */
- __u8 integer;
- /* 8 bit decimal part */
- __u8 decimal;
-};
-
-struct float_16_bit {
- /* 16 bit integer part */
- __u16 integer;
- /* 16 bit decimal part */
- __u16 decimal;
-};
-
-/*************************************************************************
- ** Color Space Conversion parameters
- *************************************************************************/
-/**
- * Structure used for CSC config params
- */
-struct vpfe_isif_color_space_conv {
- /* Enable color space conversion */
- unsigned char en;
- /**
- * csc coefficient table. S8Q5, M00 at index 0, M01 at index 1, and
- * so forth
- */
- struct float_8_bit coeff[VPFE_ISIF_CSC_NUM_COEFF];
-};
-
-enum vpfe_isif_datasft {
- /* No Shift */
- VPFE_ISIF_NO_SHIFT,
- /* 1 bit Shift */
- VPFE_ISIF_1BIT_SHIFT,
- /* 2 bit Shift */
- VPFE_ISIF_2BIT_SHIFT,
- /* 3 bit Shift */
- VPFE_ISIF_3BIT_SHIFT,
- /* 4 bit Shift */
- VPFE_ISIF_4BIT_SHIFT,
- /* 5 bit Shift */
- VPFE_ISIF_5BIT_SHIFT,
- /* 6 bit Shift */
- VPFE_ISIF_6BIT_SHIFT
-};
-
-#define VPFE_ISIF_LINEAR_TAB_SIZE 192
-/*************************************************************************
- ** Linearization parameters
- *************************************************************************/
-/**
- * Structure for Sensor data linearization
- */
-struct vpfe_isif_linearize {
- /* Enable or Disable linearization of data */
- unsigned char en;
- /* Shift value applied */
- enum vpfe_isif_datasft corr_shft;
- /* scale factor applied U11Q10 */
- struct float_16_bit scale_fact;
- /* Size of the linear table */
- unsigned short table[VPFE_ISIF_LINEAR_TAB_SIZE];
-};
-
-/*************************************************************************
- ** ISIF Raw configuration parameters
- *************************************************************************/
-enum vpfe_isif_fmt_mode {
- VPFE_ISIF_SPLIT,
- VPFE_ISIF_COMBINE
-};
-
-enum vpfe_isif_lnum {
- VPFE_ISIF_1LINE,
- VPFE_ISIF_2LINES,
- VPFE_ISIF_3LINES,
- VPFE_ISIF_4LINES
-};
-
-enum vpfe_isif_line {
- VPFE_ISIF_1STLINE,
- VPFE_ISIF_2NDLINE,
- VPFE_ISIF_3RDLINE,
- VPFE_ISIF_4THLINE
-};
-
-struct vpfe_isif_fmtplen {
- /**
- * number of program entries for SET0, range 1 - 16
- * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is
- * ISIF_COMBINE
- */
- unsigned short plen0;
- /**
- * number of program entries for SET1, range 1 - 16
- * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is
- * ISIF_COMBINE
- */
- unsigned short plen1;
- /**
- * number of program entries for SET2, range 1 - 16
- * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is
- * ISIF_COMBINE
- */
- unsigned short plen2;
- /**
- * number of program entries for SET3, range 1 - 16
- * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is
- * ISIF_COMBINE
- */
- unsigned short plen3;
-};
-
-struct vpfe_isif_fmt_cfg {
- /* Split or combine or line alternate */
- enum vpfe_isif_fmt_mode fmtmode;
- /* enable or disable line alternating mode */
- unsigned char ln_alter_en;
- /* Split/combine line number */
- enum vpfe_isif_lnum lnum;
- /* Address increment Range 1 - 16 */
- unsigned int addrinc;
-};
-
-struct vpfe_isif_fmt_addr_ptr {
- /* Initial address */
- unsigned int init_addr;
- /* output line number */
- enum vpfe_isif_line out_line;
-};
-
-struct vpfe_isif_fmtpgm_ap {
- /* program address pointer */
- unsigned char pgm_aptr;
- /* program address increment or decrement */
- unsigned char pgmupdt;
-};
-
-struct vpfe_isif_data_formatter {
- /* Enable/Disable data formatter */
- unsigned char en;
- /* data formatter configuration */
- struct vpfe_isif_fmt_cfg cfg;
- /* Formatter program entries length */
- struct vpfe_isif_fmtplen plen;
- /* first pixel in a line fed to formatter */
- unsigned short fmtrlen;
- /* HD interval for output line. Only valid when split line */
- unsigned short fmthcnt;
- /* formatter address pointers */
- struct vpfe_isif_fmt_addr_ptr fmtaddr_ptr[16];
- /* program enable/disable */
- unsigned char pgm_en[32];
- /* program address pointers */
- struct vpfe_isif_fmtpgm_ap fmtpgm_ap[32];
-};
-
-struct vpfe_isif_df_csc {
- /* Color Space Conversion configuration, 0 - csc, 1 - df */
- unsigned int df_or_csc;
- /* csc configuration valid if df_or_csc is 0 */
- struct vpfe_isif_color_space_conv csc;
- /* data formatter configuration valid if df_or_csc is 1 */
- struct vpfe_isif_data_formatter df;
- /* start pixel in a line at the input */
- unsigned int start_pix;
- /* number of pixels in input line */
- unsigned int num_pixels;
- /* start line at the input */
- unsigned int start_line;
- /* number of lines at the input */
- unsigned int num_lines;
-};
-
-struct vpfe_isif_gain_offsets_adj {
- /* Enable or Disable Gain adjustment for SDRAM data */
- unsigned char gain_sdram_en;
- /* Enable or Disable Gain adjustment for IPIPE data */
- unsigned char gain_ipipe_en;
- /* Enable or Disable Gain adjustment for H3A data */
- unsigned char gain_h3a_en;
- /* Enable or Disable Gain adjustment for SDRAM data */
- unsigned char offset_sdram_en;
- /* Enable or Disable Gain adjustment for IPIPE data */
- unsigned char offset_ipipe_en;
- /* Enable or Disable Gain adjustment for H3A data */
- unsigned char offset_h3a_en;
-};
-
-struct vpfe_isif_cul {
- /* Horizontal Cull pattern for odd lines */
- unsigned char hcpat_odd;
- /* Horizontal Cull pattern for even lines */
- unsigned char hcpat_even;
- /* Vertical Cull pattern */
- unsigned char vcpat;
- /* Enable or disable lpf. Apply when cull is enabled */
- unsigned char en_lpf;
-};
-
-/* all the stuff in this struct will be provided by userland */
-struct vpfe_isif_raw_config {
- /* Linearization parameters for image sensor data input */
- struct vpfe_isif_linearize linearize;
- /* Data formatter or CSC */
- struct vpfe_isif_df_csc df_csc;
- /* Defect Pixel Correction (DFC) confguration */
- struct vpfe_isif_dfc dfc;
- /* Black/Digital Clamp configuration */
- struct vpfe_isif_black_clamp bclamp;
- /* Gain, offset adjustments */
- struct vpfe_isif_gain_offsets_adj gain_offset;
- /* Culling */
- struct vpfe_isif_cul culling;
- /* horizontal offset for Gain/LSC/DFC */
- unsigned short horz_offset;
- /* vertical offset for Gain/LSC/DFC */
- unsigned short vert_offset;
-};
-
-/**********************************************************************
- * IPIPE API Structures
- **********************************************************************/
-
-/* IPIPE module configurations */
-
-/* IPIPE input configuration */
-#define VPFE_IPIPE_INPUT_CONFIG BIT(0)
-/* LUT based Defect Pixel Correction */
-#define VPFE_IPIPE_LUTDPC BIT(1)
-/* On the fly (OTF) Defect Pixel Correction */
-#define VPFE_IPIPE_OTFDPC BIT(2)
-/* Noise Filter - 1 */
-#define VPFE_IPIPE_NF1 BIT(3)
-/* Noise Filter - 2 */
-#define VPFE_IPIPE_NF2 BIT(4)
-/* White Balance. Also a control ID */
-#define VPFE_IPIPE_WB BIT(5)
-/* 1st RGB to RBG Blend module */
-#define VPFE_IPIPE_RGB2RGB_1 BIT(6)
-/* 2nd RGB to RBG Blend module */
-#define VPFE_IPIPE_RGB2RGB_2 BIT(7)
-/* Gamma Correction */
-#define VPFE_IPIPE_GAMMA BIT(8)
-/* 3D LUT color conversion */
-#define VPFE_IPIPE_3D_LUT BIT(9)
-/* RGB to YCbCr module */
-#define VPFE_IPIPE_RGB2YUV BIT(10)
-/* YUV 422 conversion module */
-#define VPFE_IPIPE_YUV422_CONV BIT(11)
-/* Edge Enhancement */
-#define VPFE_IPIPE_YEE BIT(12)
-/* Green Imbalance Correction */
-#define VPFE_IPIPE_GIC BIT(13)
-/* CFA Interpolation */
-#define VPFE_IPIPE_CFA BIT(14)
-/* Chroma Artifact Reduction */
-#define VPFE_IPIPE_CAR BIT(15)
-/* Chroma Gain Suppression */
-#define VPFE_IPIPE_CGS BIT(16)
-/* Global brightness and contrast control */
-#define VPFE_IPIPE_GBCE BIT(17)
-
-#define VPFE_IPIPE_MAX_MODULES 18
-
-struct ipipe_float_u16 {
- unsigned short integer;
- unsigned short decimal;
-};
-
-struct ipipe_float_s16 {
- short integer;
- unsigned short decimal;
-};
-
-struct ipipe_float_u8 {
- unsigned char integer;
- unsigned char decimal;
-};
-
-/* Copy method selection for vertical correction
- * Used when ipipe_dfc_corr_meth is IPIPE_DPC_CTORB_AFTER_HINT
- */
-enum vpfe_ipipe_dpc_corr_meth {
- /* replace by black or white dot specified by repl_white */
- VPFE_IPIPE_DPC_REPL_BY_DOT = 0,
- /* Copy from left */
- VPFE_IPIPE_DPC_CL = 1,
- /* Copy from right */
- VPFE_IPIPE_DPC_CR = 2,
- /* Horizontal interpolation */
- VPFE_IPIPE_DPC_H_INTP = 3,
- /* Vertical interpolation */
- VPFE_IPIPE_DPC_V_INTP = 4,
- /* Copy from top */
- VPFE_IPIPE_DPC_CT = 5,
- /* Copy from bottom */
- VPFE_IPIPE_DPC_CB = 6,
- /* 2D interpolation */
- VPFE_IPIPE_DPC_2D_INTP = 7,
-};
-
-struct vpfe_ipipe_lutdpc_entry {
- /* Horizontal position */
- unsigned short horz_pos;
- /* vertical position */
- unsigned short vert_pos;
- enum vpfe_ipipe_dpc_corr_meth method;
-};
-
-#define VPFE_IPIPE_MAX_SIZE_DPC 256
-
-/* Structure for configuring DPC module */
-struct vpfe_ipipe_lutdpc {
- /* 0 - disable, 1 - enable */
- unsigned char en;
- /* 0 - replace with black dot, 1 - white dot when correction
- * method is IPIPE_DFC_REPL_BY_DOT=0,
- */
- unsigned char repl_white;
- /* number of entries in the correction table. Currently only
- * support up-to 256 entries. infinite mode is not supported
- */
- unsigned short dpc_size;
- struct vpfe_ipipe_lutdpc_entry table[VPFE_IPIPE_MAX_SIZE_DPC];
-};
-
-enum vpfe_ipipe_otfdpc_det_meth {
- VPFE_IPIPE_DPC_OTF_MIN_MAX,
- VPFE_IPIPE_DPC_OTF_MIN_MAX2
-};
-
-struct vpfe_ipipe_otfdpc_thr {
- unsigned short r;
- unsigned short gr;
- unsigned short gb;
- unsigned short b;
-};
-
-enum vpfe_ipipe_otfdpc_alg {
- VPFE_IPIPE_OTFDPC_2_0,
- VPFE_IPIPE_OTFDPC_3_0
-};
-
-struct vpfe_ipipe_otfdpc_2_0_cfg {
- /* defect detection threshold for MIN_MAX2 method (DPC 2.0 alg) */
- struct vpfe_ipipe_otfdpc_thr det_thr;
- /* defect correction threshold for MIN_MAX2 method (DPC 2.0 alg) or
- * maximum value for MIN_MAX method
- */
- struct vpfe_ipipe_otfdpc_thr corr_thr;
-};
-
-struct vpfe_ipipe_otfdpc_3_0_cfg {
- /* DPC3.0 activity adj shf. activity = (max2-min2) >> (6 -shf)
- */
- unsigned char act_adj_shf;
- /* DPC3.0 detection threshold, THR */
- unsigned short det_thr;
- /* DPC3.0 detection threshold slope, SLP */
- unsigned short det_slp;
- /* DPC3.0 detection threshold min, MIN */
- unsigned short det_thr_min;
- /* DPC3.0 detection threshold max, MAX */
- unsigned short det_thr_max;
- /* DPC3.0 correction threshold, THR */
- unsigned short corr_thr;
- /* DPC3.0 correction threshold slope, SLP */
- unsigned short corr_slp;
- /* DPC3.0 correction threshold min, MIN */
- unsigned short corr_thr_min;
- /* DPC3.0 correction threshold max, MAX */
- unsigned short corr_thr_max;
-};
-
-struct vpfe_ipipe_otfdpc {
- /* 0 - disable, 1 - enable */
- unsigned char en;
- /* defect detection method */
- enum vpfe_ipipe_otfdpc_det_meth det_method;
- /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is
- * used
- */
- enum vpfe_ipipe_otfdpc_alg alg;
- union {
- /* if alg is IPIPE_OTFDPC_2_0 */
- struct vpfe_ipipe_otfdpc_2_0_cfg dpc_2_0;
- /* if alg is IPIPE_OTFDPC_3_0 */
- struct vpfe_ipipe_otfdpc_3_0_cfg dpc_3_0;
- } alg_cfg;
-};
-
-/* Threshold values table size */
-#define VPFE_IPIPE_NF_THR_TABLE_SIZE 8
-/* Intensity values table size */
-#define VPFE_IPIPE_NF_STR_TABLE_SIZE 8
-
-/* NF, sampling method for green pixels */
-enum vpfe_ipipe_nf_sampl_meth {
- /* Same as R or B */
- VPFE_IPIPE_NF_BOX,
- /* Diamond mode */
- VPFE_IPIPE_NF_DIAMOND
-};
-
-/* Structure for configuring NF module */
-struct vpfe_ipipe_nf {
- /* 0 - disable, 1 - enable */
- unsigned char en;
- /* Sampling method for green pixels */
- enum vpfe_ipipe_nf_sampl_meth gr_sample_meth;
- /* Down shift value in LUT reference address
- */
- unsigned char shft_val;
- /* Spread value in NF algorithm
- */
- unsigned char spread_val;
- /* Apply LSC gain to threshold. Enable this only if
- * LSC is enabled in ISIF
- */
- unsigned char apply_lsc_gain;
- /* Threshold values table */
- unsigned short thr[VPFE_IPIPE_NF_THR_TABLE_SIZE];
- /* intensity values table */
- unsigned char str[VPFE_IPIPE_NF_STR_TABLE_SIZE];
- /* Edge detection minimum threshold */
- unsigned short edge_det_min_thr;
- /* Edge detection maximum threshold */
- unsigned short edge_det_max_thr;
-};
-
-enum vpfe_ipipe_gic_alg {
- VPFE_IPIPE_GIC_ALG_CONST_GAIN,
- VPFE_IPIPE_GIC_ALG_ADAPT_GAIN
-};
-
-enum vpfe_ipipe_gic_thr_sel {
- VPFE_IPIPE_GIC_THR_REG,
- VPFE_IPIPE_GIC_THR_NF
-};
-
-enum vpfe_ipipe_gic_wt_fn_type {
- /* Use difference as index */
- VPFE_IPIPE_GIC_WT_FN_TYP_DIF,
- /* Use weight function as index */
- VPFE_IPIPE_GIC_WT_FN_TYP_HP_VAL
-};
-
-/* structure for Green Imbalance Correction */
-struct vpfe_ipipe_gic {
- /* 0 - disable, 1 - enable */
- unsigned char en;
- /* 0 - Constant gain , 1 - Adaptive gain algorithm */
- enum vpfe_ipipe_gic_alg gic_alg;
- /* GIC gain or weight. Used for Constant gain and Adaptive algorithms
- */
- unsigned short gain;
- /* Threshold selection. GIC register values or NF2 thr table */
- enum vpfe_ipipe_gic_thr_sel thr_sel;
- /* thr1. Used when thr_sel is IPIPE_GIC_THR_REG */
- unsigned short thr;
- /* this value is used for thr2-thr1, thr3-thr2 or
- * thr4-thr3 when wt_fn_type is index. Otherwise it
- * is the
- */
- unsigned short slope;
- /* Apply LSC gain to threshold. Enable this only if
- * LSC is enabled in ISIF & thr_sel is IPIPE_GIC_THR_REG
- */
- unsigned char apply_lsc_gain;
- /* Multiply Nf2 threshold by this gain. Use this when thr_sel
- * is IPIPE_GIC_THR_NF
- */
- struct ipipe_float_u8 nf2_thr_gain;
- /* Weight function uses difference as index or high pass value.
- * Used for adaptive gain algorithm
- */
- enum vpfe_ipipe_gic_wt_fn_type wt_fn_type;
-};
-
-/* Structure for configuring WB module */
-struct vpfe_ipipe_wb {
- /* Offset (S12) for R */
- short ofst_r;
- /* Offset (S12) for Gr */
- short ofst_gr;
- /* Offset (S12) for Gb */
- short ofst_gb;
- /* Offset (S12) for B */
- short ofst_b;
- /* Gain (U13Q9) for Red */
- struct ipipe_float_u16 gain_r;
- /* Gain (U13Q9) for Gr */
- struct ipipe_float_u16 gain_gr;
- /* Gain (U13Q9) for Gb */
- struct ipipe_float_u16 gain_gb;
- /* Gain (U13Q9) for Blue */
- struct ipipe_float_u16 gain_b;
-};
-
-enum vpfe_ipipe_cfa_alg {
- /* Algorithm is 2DirAC */
- VPFE_IPIPE_CFA_ALG_2DIRAC,
- /* Algorithm is 2DirAC + Digital Antialiasing (DAA) */
- VPFE_IPIPE_CFA_ALG_2DIRAC_DAA,
- /* Algorithm is DAA */
- VPFE_IPIPE_CFA_ALG_DAA
-};
-
-/* Structure for CFA Interpolation */
-struct vpfe_ipipe_cfa {
- /* 2DirAC or 2DirAC + DAA */
- enum vpfe_ipipe_cfa_alg alg;
- /* 2Dir CFA HP value Low Threshold */
- unsigned short hpf_thr_2dir;
- /* 2Dir CFA HP value slope */
- unsigned short hpf_slp_2dir;
- /* 2Dir CFA HP mix threshold */
- unsigned short hp_mix_thr_2dir;
- /* 2Dir CFA HP mix slope */
- unsigned short hp_mix_slope_2dir;
- /* 2Dir Direction threshold */
- unsigned short dir_thr_2dir;
- /* 2Dir Direction slope */
- unsigned short dir_slope_2dir;
- /* 2Dir Non Directional Weight */
- unsigned short nd_wt_2dir;
- /* DAA Mono Hue Fraction */
- unsigned short hue_fract_daa;
- /* DAA Mono Edge threshold */
- unsigned short edge_thr_daa;
- /* DAA Mono threshold minimum */
- unsigned short thr_min_daa;
- /* DAA Mono threshold slope */
- unsigned short thr_slope_daa;
- /* DAA Mono slope minimum */
- unsigned short slope_min_daa;
- /* DAA Mono slope slope */
- unsigned short slope_slope_daa;
- /* DAA Mono LP wight */
- unsigned short lp_wt_daa;
-};
-
-/* Struct for configuring RGB2RGB blending module */
-struct vpfe_ipipe_rgb2rgb {
- /* Matrix coefficient for RR S12Q8 for ID = 1 and S11Q8 for ID = 2 */
- struct ipipe_float_s16 coef_rr;
- /* Matrix coefficient for GR S12Q8/S11Q8 */
- struct ipipe_float_s16 coef_gr;
- /* Matrix coefficient for BR S12Q8/S11Q8 */
- struct ipipe_float_s16 coef_br;
- /* Matrix coefficient for RG S12Q8/S11Q8 */
- struct ipipe_float_s16 coef_rg;
- /* Matrix coefficient for GG S12Q8/S11Q8 */
- struct ipipe_float_s16 coef_gg;
- /* Matrix coefficient for BG S12Q8/S11Q8 */
- struct ipipe_float_s16 coef_bg;
- /* Matrix coefficient for RB S12Q8/S11Q8 */
- struct ipipe_float_s16 coef_rb;
- /* Matrix coefficient for GB S12Q8/S11Q8 */
- struct ipipe_float_s16 coef_gb;
- /* Matrix coefficient for BB S12Q8/S11Q8 */
- struct ipipe_float_s16 coef_bb;
- /* Output offset for R S13/S11 */
- int out_ofst_r;
- /* Output offset for G S13/S11 */
- int out_ofst_g;
- /* Output offset for B S13/S11 */
- int out_ofst_b;
-};
-
-#define VPFE_IPIPE_MAX_SIZE_GAMMA 512
-
-enum vpfe_ipipe_gamma_tbl_size {
- VPFE_IPIPE_GAMMA_TBL_SZ_64 = 64,
- VPFE_IPIPE_GAMMA_TBL_SZ_128 = 128,
- VPFE_IPIPE_GAMMA_TBL_SZ_256 = 256,
- VPFE_IPIPE_GAMMA_TBL_SZ_512 = 512,
-};
-
-enum vpfe_ipipe_gamma_tbl_sel {
- VPFE_IPIPE_GAMMA_TBL_RAM = 0,
- VPFE_IPIPE_GAMMA_TBL_ROM = 1,
-};
-
-struct vpfe_ipipe_gamma_entry {
- /* 10 bit slope */
- short slope;
- /* 10 bit offset */
- unsigned short offset;
-};
-
-/* Structure for configuring Gamma correction module */
-struct vpfe_ipipe_gamma {
- /* 0 - Enable Gamma correction for Red
- * 1 - bypass Gamma correction. Data is divided by 16
- */
- unsigned char bypass_r;
- /* 0 - Enable Gamma correction for Blue
- * 1 - bypass Gamma correction. Data is divided by 16
- */
- unsigned char bypass_b;
- /* 0 - Enable Gamma correction for Green
- * 1 - bypass Gamma correction. Data is divided by 16
- */
- unsigned char bypass_g;
- /* IPIPE_GAMMA_TBL_RAM or IPIPE_GAMMA_TBL_ROM */
- enum vpfe_ipipe_gamma_tbl_sel tbl_sel;
- /* Table size for RAM gamma table.
- */
- enum vpfe_ipipe_gamma_tbl_size tbl_size;
- /* R table */
- struct vpfe_ipipe_gamma_entry table_r[VPFE_IPIPE_MAX_SIZE_GAMMA];
- /* Blue table */
- struct vpfe_ipipe_gamma_entry table_b[VPFE_IPIPE_MAX_SIZE_GAMMA];
- /* Green table */
- struct vpfe_ipipe_gamma_entry table_g[VPFE_IPIPE_MAX_SIZE_GAMMA];
-};
-
-#define VPFE_IPIPE_MAX_SIZE_3D_LUT 729
-
-struct vpfe_ipipe_3d_lut_entry {
- /* 10 bit entry for red */
- unsigned short r;
- /* 10 bit entry for green */
- unsigned short g;
- /* 10 bit entry for blue */
- unsigned short b;
-};
-
-/* structure for 3D-LUT */
-struct vpfe_ipipe_3d_lut {
- /* enable/disable 3D lut */
- unsigned char en;
- /* 3D - LUT table entry */
- struct vpfe_ipipe_3d_lut_entry table[VPFE_IPIPE_MAX_SIZE_3D_LUT];
-};
-
-/* Struct for configuring rgb2ycbcr module */
-struct vpfe_ipipe_rgb2yuv {
- /* Matrix coefficient for RY S12Q8 */
- struct ipipe_float_s16 coef_ry;
- /* Matrix coefficient for GY S12Q8 */
- struct ipipe_float_s16 coef_gy;
- /* Matrix coefficient for BY S12Q8 */
- struct ipipe_float_s16 coef_by;
- /* Matrix coefficient for RCb S12Q8 */
- struct ipipe_float_s16 coef_rcb;
- /* Matrix coefficient for GCb S12Q8 */
- struct ipipe_float_s16 coef_gcb;
- /* Matrix coefficient for BCb S12Q8 */
- struct ipipe_float_s16 coef_bcb;
- /* Matrix coefficient for RCr S12Q8 */
- struct ipipe_float_s16 coef_rcr;
- /* Matrix coefficient for GCr S12Q8 */
- struct ipipe_float_s16 coef_gcr;
- /* Matrix coefficient for BCr S12Q8 */
- struct ipipe_float_s16 coef_bcr;
- /* Output offset for R S11 */
- int out_ofst_y;
- /* Output offset for Cb S11 */
- int out_ofst_cb;
- /* Output offset for Cr S11 */
- int out_ofst_cr;
-};
-
-enum vpfe_ipipe_gbce_type {
- VPFE_IPIPE_GBCE_Y_VAL_TBL = 0,
- VPFE_IPIPE_GBCE_GAIN_TBL = 1,
-};
-
-#define VPFE_IPIPE_MAX_SIZE_GBCE_LUT 1024
-
-/* structure for Global brightness and Contrast */
-struct vpfe_ipipe_gbce {
- /* enable/disable GBCE */
- unsigned char en;
- /* Y - value table or Gain table */
- enum vpfe_ipipe_gbce_type type;
- /* ptr to LUT for GBCE with 1024 entries */
- unsigned short table[VPFE_IPIPE_MAX_SIZE_GBCE_LUT];
-};
-
-/* Chrominance position. Applicable only for YCbCr input
- * Applied after edge enhancement
- */
-enum vpfe_chr_pos {
- /* Co-siting, same position with luminance */
- VPFE_IPIPE_YUV422_CHR_POS_COSITE = 0,
- /* Centering, In the middle of luminance */
- VPFE_IPIPE_YUV422_CHR_POS_CENTRE = 1,
-};
-
-/* Structure for configuring yuv422 conversion module */
-struct vpfe_ipipe_yuv422_conv {
- /* Max Chrominance value */
- unsigned char en_chrom_lpf;
- /* 1 - enable LPF for chrminance, 0 - disable */
- enum vpfe_chr_pos chrom_pos;
-};
-
-#define VPFE_IPIPE_MAX_SIZE_YEE_LUT 1024
-
-enum vpfe_ipipe_yee_merge_meth {
- VPFE_IPIPE_YEE_ABS_MAX = 0,
- VPFE_IPIPE_YEE_EE_ES = 1,
-};
-
-/* Structure for configuring YUV Edge Enhancement module */
-struct vpfe_ipipe_yee {
- /* 1 - enable enhancement, 0 - disable */
- unsigned char en;
- /* enable/disable halo reduction in edge sharpner */
- unsigned char en_halo_red;
- /* Merge method between Edge Enhancer and Edge sharpner */
- enum vpfe_ipipe_yee_merge_meth merge_meth;
- /* HPF Shift length */
- unsigned char hpf_shft;
- /* HPF Coefficient 00, S10 */
- short hpf_coef_00;
- /* HPF Coefficient 01, S10 */
- short hpf_coef_01;
- /* HPF Coefficient 02, S10 */
- short hpf_coef_02;
- /* HPF Coefficient 10, S10 */
- short hpf_coef_10;
- /* HPF Coefficient 11, S10 */
- short hpf_coef_11;
- /* HPF Coefficient 12, S10 */
- short hpf_coef_12;
- /* HPF Coefficient 20, S10 */
- short hpf_coef_20;
- /* HPF Coefficient 21, S10 */
- short hpf_coef_21;
- /* HPF Coefficient 22, S10 */
- short hpf_coef_22;
- /* Lower threshold before referring to LUT */
- unsigned short yee_thr;
- /* Edge sharpener Gain */
- unsigned short es_gain;
- /* Edge sharpener lower threshold */
- unsigned short es_thr1;
- /* Edge sharpener upper threshold */
- unsigned short es_thr2;
- /* Edge sharpener gain on gradient */
- unsigned short es_gain_grad;
- /* Edge sharpener offset on gradient */
- unsigned short es_ofst_grad;
- /* Ptr to EE table. Must have 1024 entries */
- short table[VPFE_IPIPE_MAX_SIZE_YEE_LUT];
-};
-
-enum vpfe_ipipe_car_meth {
- /* Chromatic Gain Control */
- VPFE_IPIPE_CAR_CHR_GAIN_CTRL = 0,
- /* Dynamic switching between CHR_GAIN_CTRL
- * and MED_FLTR
- */
- VPFE_IPIPE_CAR_DYN_SWITCH = 1,
- /* Median Filter */
- VPFE_IPIPE_CAR_MED_FLTR = 2,
-};
-
-enum vpfe_ipipe_car_hpf_type {
- VPFE_IPIPE_CAR_HPF_Y = 0,
- VPFE_IPIPE_CAR_HPF_H = 1,
- VPFE_IPIPE_CAR_HPF_V = 2,
- VPFE_IPIPE_CAR_HPF_2D = 3,
- /* 2D HPF from YUV Edge Enhancement */
- VPFE_IPIPE_CAR_HPF_2D_YEE = 4,
-};
-
-struct vpfe_ipipe_car_gain {
- /* csup_gain */
- unsigned char gain;
- /* csup_shf. */
- unsigned char shft;
- /* gain minimum */
- unsigned short gain_min;
-};
-
-/* Structure for Chromatic Artifact Reduction */
-struct vpfe_ipipe_car {
- /* enable/disable */
- unsigned char en;
- /* Gain control or Dynamic switching */
- enum vpfe_ipipe_car_meth meth;
- /* Gain1 function configuration for Gain control */
- struct vpfe_ipipe_car_gain gain1;
- /* Gain2 function configuration for Gain control */
- struct vpfe_ipipe_car_gain gain2;
- /* HPF type used for CAR */
- enum vpfe_ipipe_car_hpf_type hpf;
- /* csup_thr: HPF threshold for Gain control */
- unsigned char hpf_thr;
- /* Down shift value for hpf. 2 bits */
- unsigned char hpf_shft;
- /* switch limit for median filter */
- unsigned char sw0;
- /* switch coefficient for Gain control */
- unsigned char sw1;
-};
-
-/* structure for Chromatic Gain Suppression */
-struct vpfe_ipipe_cgs {
- /* enable/disable */
- unsigned char en;
- /* gain1 bright side threshold */
- unsigned char h_thr;
- /* gain1 bright side slope */
- unsigned char h_slope;
- /* gain1 down shift value for bright side */
- unsigned char h_shft;
- /* gain1 bright side minimum gain */
- unsigned char h_min;
-};
-
-/* Max pixels allowed in the input. If above this either decimation
- * or frame division mode to be enabled
- */
-#define VPFE_IPIPE_MAX_INPUT_WIDTH 2600
-
-struct vpfe_ipipe_input_config {
- unsigned int vst;
- unsigned int hst;
-};
-
-/**
- * struct vpfe_ipipe_config - IPIPE engine configuration (user)
- * @input_config: Pointer to structure for ipipe configuration.
- * @flag: Specifies which ISP IPIPE functions should be enabled.
- * @lutdpc: Pointer to luma enhancement structure.
- * @otfdpc: Pointer to structure for defect correction.
- * @nf1: Pointer to structure for Noise Filter.
- * @nf2: Pointer to structure for Noise Filter.
- * @gic: Pointer to structure for Green Imbalance.
- * @wbal: Pointer to structure for White Balance.
- * @cfa: Pointer to structure containing the CFA interpolation.
- * @rgb2rgb1: Pointer to structure for RGB to RGB Blending.
- * @rgb2rgb2: Pointer to structure for RGB to RGB Blending.
- * @gamma: Pointer to gamma structure.
- * @lut: Pointer to structure for 3D LUT.
- * @rgb2yuv: Pointer to structure for RGB-YCbCr conversion.
- * @gbce: Pointer to structure for Global Brightness,Contrast Control.
- * @yuv422_conv: Pointer to structure for YUV 422 conversion.
- * @yee: Pointer to structure for Edge Enhancer.
- * @car: Pointer to structure for Chromatic Artifact Reduction.
- * @cgs: Pointer to structure for Chromatic Gain Suppression.
- */
-struct vpfe_ipipe_config {
- __u32 flag;
- struct vpfe_ipipe_input_config __user *input_config;
- struct vpfe_ipipe_lutdpc __user *lutdpc;
- struct vpfe_ipipe_otfdpc __user *otfdpc;
- struct vpfe_ipipe_nf __user *nf1;
- struct vpfe_ipipe_nf __user *nf2;
- struct vpfe_ipipe_gic __user *gic;
- struct vpfe_ipipe_wb __user *wbal;
- struct vpfe_ipipe_cfa __user *cfa;
- struct vpfe_ipipe_rgb2rgb __user *rgb2rgb1;
- struct vpfe_ipipe_rgb2rgb __user *rgb2rgb2;
- struct vpfe_ipipe_gamma __user *gamma;
- struct vpfe_ipipe_3d_lut __user *lut;
- struct vpfe_ipipe_rgb2yuv __user *rgb2yuv;
- struct vpfe_ipipe_gbce __user *gbce;
- struct vpfe_ipipe_yuv422_conv __user *yuv422_conv;
- struct vpfe_ipipe_yee __user *yee;
- struct vpfe_ipipe_car __user *car;
- struct vpfe_ipipe_cgs __user *cgs;
-};
-
-/*******************************************************************
- ** Resizer API structures
- *******************************************************************/
-/* Interpolation types used for horizontal rescale */
-enum vpfe_rsz_intp_t {
- VPFE_RSZ_INTP_CUBIC,
- VPFE_RSZ_INTP_LINEAR
-};
-
-/* Horizontal LPF intensity selection */
-enum vpfe_rsz_h_lpf_lse_t {
- VPFE_RSZ_H_LPF_LSE_INTERN,
- VPFE_RSZ_H_LPF_LSE_USER_VAL
-};
-
-enum vpfe_rsz_down_scale_ave_sz {
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- VPFE_IPIPE_DWN_SCALE_1_OVER_4,
- VPFE_IPIPE_DWN_SCALE_1_OVER_8,
- VPFE_IPIPE_DWN_SCALE_1_OVER_16,
- VPFE_IPIPE_DWN_SCALE_1_OVER_32,
- VPFE_IPIPE_DWN_SCALE_1_OVER_64,
- VPFE_IPIPE_DWN_SCALE_1_OVER_128,
- VPFE_IPIPE_DWN_SCALE_1_OVER_256
-};
-
-struct vpfe_rsz_output_spec {
- /* enable horizontal flip */
- unsigned char h_flip;
- /* enable vertical flip */
- unsigned char v_flip;
- /* line start offset for y. */
- unsigned int vst_y;
- /* line start offset for c. Only for 420 */
- unsigned int vst_c;
- /* vertical rescale interpolation type, YCbCr or Luminance */
- enum vpfe_rsz_intp_t v_typ_y;
- /* vertical rescale interpolation type for Chrominance */
- enum vpfe_rsz_intp_t v_typ_c;
- /* vertical lpf intensity - Luminance */
- unsigned char v_lpf_int_y;
- /* vertical lpf intensity - Chrominance */
- unsigned char v_lpf_int_c;
- /* horizontal rescale interpolation types, YCbCr or Luminance */
- enum vpfe_rsz_intp_t h_typ_y;
- /* horizontal rescale interpolation types, Chrominance */
- enum vpfe_rsz_intp_t h_typ_c;
- /* horizontal lpf intensity - Luminance */
- unsigned char h_lpf_int_y;
- /* horizontal lpf intensity - Chrominance */
- unsigned char h_lpf_int_c;
- /* Use down scale mode for scale down */
- unsigned char en_down_scale;
- /* if downscale, set the downscale more average size for horizontal
- * direction. Used only if output width and height is less than
- * input sizes
- */
- enum vpfe_rsz_down_scale_ave_sz h_dscale_ave_sz;
- /* if downscale, set the downscale more average size for vertical
- * direction. Used only if output width and height is less than
- * input sizes
- */
- enum vpfe_rsz_down_scale_ave_sz v_dscale_ave_sz;
- /* Y offset. If set, the offset would be added to the base address
- */
- unsigned int user_y_ofst;
- /* C offset. If set, the offset would be added to the base address
- */
- unsigned int user_c_ofst;
-};
-
-struct vpfe_rsz_config_params {
- unsigned int vst;
- /* horizontal start position of the image
- * data to IPIPE
- */
- unsigned int hst;
- /* output spec of the image data coming out of resizer - 0(UYVY).
- */
- struct vpfe_rsz_output_spec output1;
- /* output spec of the image data coming out of resizer - 1(UYVY).
- */
- struct vpfe_rsz_output_spec output2;
- /* 0 , chroma sample at odd pixel, 1 - even pixel */
- unsigned char chroma_sample_even;
- unsigned char frame_div_mode_en;
- unsigned char yuv_y_min;
- unsigned char yuv_y_max;
- unsigned char yuv_c_min;
- unsigned char yuv_c_max;
- enum vpfe_chr_pos out_chr_pos;
- unsigned char bypass;
-};
-
-/* Structure for VIDIOC_VPFE_RSZ_[S/G]_CONFIG IOCTLs */
-struct vpfe_rsz_config {
- struct vpfe_rsz_config_params *config;
-};
-
-#endif /* _DAVINCI_VPFE_USER_H */
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
deleted file mode 100644
index 52397ad0e3e2..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ /dev/null
@@ -1,1852 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- *
- *
- * IPIPE allows fine tuning of the input image using different
- * tuning modules in IPIPE. Some examples :- Noise filter, Defect
- * pixel correction etc. It essentially operate on Bayer Raw data
- * or YUV raw data. To do image tuning, application call,
- *
- */
-
-#include <linux/slab.h>
-#include <linux/bitops.h>
-
-#include "dm365_ipipe.h"
-#include "dm365_ipipe_hw.h"
-#include "vpfe_mc_capture.h"
-
-#define MIN_OUT_WIDTH 32
-#define MIN_OUT_HEIGHT 32
-
-/* ipipe input format's */
-static const unsigned int ipipe_input_fmts[] = {
- MEDIA_BUS_FMT_UYVY8_2X8,
- MEDIA_BUS_FMT_SGRBG12_1X12,
- MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
- MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
-};
-
-/* ipipe output format's */
-static const unsigned int ipipe_output_fmts[] = {
- MEDIA_BUS_FMT_UYVY8_2X8,
-};
-
-static int ipipe_validate_lutdpc_params(struct vpfe_ipipe_lutdpc *lutdpc)
-{
- int i;
-
- if (lutdpc->en > 1 || lutdpc->repl_white > 1 ||
- lutdpc->dpc_size > LUT_DPC_MAX_SIZE)
- return -EINVAL;
-
- if (lutdpc->en)
- return -EINVAL;
-
- for (i = 0; i < lutdpc->dpc_size; i++)
- if (lutdpc->table[i].horz_pos > LUT_DPC_H_POS_MASK ||
- lutdpc->table[i].vert_pos > LUT_DPC_V_POS_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_lutdpc_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_lutdpc *lutdpc = &ipipe->config.lutdpc;
- struct vpfe_ipipe_lutdpc *dpc_param;
-
- if (!param) {
- memset((void *)lutdpc, 0, sizeof(struct vpfe_ipipe_lutdpc));
- goto success;
- }
-
- dpc_param = param;
- lutdpc->en = dpc_param->en;
- lutdpc->repl_white = dpc_param->repl_white;
- lutdpc->dpc_size = dpc_param->dpc_size;
- memcpy(&lutdpc->table, &dpc_param->table,
- (dpc_param->dpc_size * sizeof(struct vpfe_ipipe_lutdpc_entry)));
- if (ipipe_validate_lutdpc_params(lutdpc) < 0)
- return -EINVAL;
-
-success:
- ipipe_set_lutdpc_regs(ipipe->base_addr, ipipe->isp5_base_addr, lutdpc);
-
- return 0;
-}
-
-static int ipipe_get_lutdpc_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_lutdpc *lut_param = param;
- struct vpfe_ipipe_lutdpc *lutdpc = &ipipe->config.lutdpc;
-
- lut_param->en = lutdpc->en;
- lut_param->repl_white = lutdpc->repl_white;
- lut_param->dpc_size = lutdpc->dpc_size;
- memcpy(&lut_param->table, &lutdpc->table,
- (lutdpc->dpc_size * sizeof(struct vpfe_ipipe_lutdpc_entry)));
-
- return 0;
-}
-
-static int ipipe_set_input_config(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_input_config *config = &ipipe->config.input_config;
-
- if (!param)
- memset(config, 0, sizeof(struct vpfe_ipipe_input_config));
- else
- memcpy(config, param, sizeof(struct vpfe_ipipe_input_config));
- return 0;
-}
-
-static int ipipe_get_input_config(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_input_config *config = &ipipe->config.input_config;
-
- if (!param)
- return -EINVAL;
-
- memcpy(param, config, sizeof(struct vpfe_ipipe_input_config));
-
- return 0;
-}
-
-static int ipipe_validate_otfdpc_params(struct vpfe_ipipe_otfdpc *dpc_param)
-{
- struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_2_0;
- struct vpfe_ipipe_otfdpc_3_0_cfg *dpc_3_0;
-
- if (dpc_param->en > 1)
- return -EINVAL;
-
- if (dpc_param->alg == VPFE_IPIPE_OTFDPC_2_0) {
- dpc_2_0 = &dpc_param->alg_cfg.dpc_2_0;
- if (dpc_2_0->det_thr.r > OTFDPC_DPC2_THR_MASK ||
- dpc_2_0->det_thr.gr > OTFDPC_DPC2_THR_MASK ||
- dpc_2_0->det_thr.gb > OTFDPC_DPC2_THR_MASK ||
- dpc_2_0->det_thr.b > OTFDPC_DPC2_THR_MASK ||
- dpc_2_0->corr_thr.r > OTFDPC_DPC2_THR_MASK ||
- dpc_2_0->corr_thr.gr > OTFDPC_DPC2_THR_MASK ||
- dpc_2_0->corr_thr.gb > OTFDPC_DPC2_THR_MASK ||
- dpc_2_0->corr_thr.b > OTFDPC_DPC2_THR_MASK)
- return -EINVAL;
- return 0;
- }
-
- dpc_3_0 = &dpc_param->alg_cfg.dpc_3_0;
-
- if (dpc_3_0->act_adj_shf > OTF_DPC3_0_SHF_MASK ||
- dpc_3_0->det_thr > OTF_DPC3_0_DET_MASK ||
- dpc_3_0->det_slp > OTF_DPC3_0_SLP_MASK ||
- dpc_3_0->det_thr_min > OTF_DPC3_0_DET_MASK ||
- dpc_3_0->det_thr_max > OTF_DPC3_0_DET_MASK ||
- dpc_3_0->corr_thr > OTF_DPC3_0_CORR_MASK ||
- dpc_3_0->corr_slp > OTF_DPC3_0_SLP_MASK ||
- dpc_3_0->corr_thr_min > OTF_DPC3_0_CORR_MASK ||
- dpc_3_0->corr_thr_max > OTF_DPC3_0_CORR_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_otfdpc_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_otfdpc *dpc_param = param;
- struct vpfe_ipipe_otfdpc *otfdpc = &ipipe->config.otfdpc;
- struct device *dev;
-
- if (!param) {
- memset((void *)otfdpc, 0, sizeof(struct ipipe_otfdpc_2_0));
- goto success;
- }
- dev = ipipe->subdev.v4l2_dev->dev;
- memcpy(otfdpc, dpc_param, sizeof(struct vpfe_ipipe_otfdpc));
- if (ipipe_validate_otfdpc_params(otfdpc) < 0) {
- dev_err(dev, "Invalid otfdpc params\n");
- return -EINVAL;
- }
-
-success:
- ipipe_set_otfdpc_regs(ipipe->base_addr, otfdpc);
-
- return 0;
-}
-
-static int ipipe_get_otfdpc_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_otfdpc *dpc_param = param;
- struct vpfe_ipipe_otfdpc *otfdpc = &ipipe->config.otfdpc;
-
- memcpy(dpc_param, otfdpc, sizeof(struct vpfe_ipipe_otfdpc));
- return 0;
-}
-
-static int ipipe_validate_nf_params(struct vpfe_ipipe_nf *nf_param)
-{
- int i;
-
- if (nf_param->en > 1 || nf_param->shft_val > D2F_SHFT_VAL_MASK ||
- nf_param->spread_val > D2F_SPR_VAL_MASK ||
- nf_param->apply_lsc_gain > 1 ||
- nf_param->edge_det_min_thr > D2F_EDGE_DET_THR_MASK ||
- nf_param->edge_det_max_thr > D2F_EDGE_DET_THR_MASK)
- return -EINVAL;
-
- for (i = 0; i < VPFE_IPIPE_NF_THR_TABLE_SIZE; i++)
- if (nf_param->thr[i] > D2F_THR_VAL_MASK)
- return -EINVAL;
-
- for (i = 0; i < VPFE_IPIPE_NF_STR_TABLE_SIZE; i++)
- if (nf_param->str[i] > D2F_STR_VAL_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_nf_params(struct vpfe_ipipe_device *ipipe,
- unsigned int id, void *param)
-{
- struct vpfe_ipipe_nf *nf_param = param;
- struct vpfe_ipipe_nf *nf = &ipipe->config.nf1;
- struct device *dev;
-
- if (id == IPIPE_D2F_2ND)
- nf = &ipipe->config.nf2;
-
- if (!nf_param) {
- memset((void *)nf, 0, sizeof(struct vpfe_ipipe_nf));
- goto success;
- }
-
- dev = ipipe->subdev.v4l2_dev->dev;
- memcpy(nf, nf_param, sizeof(struct vpfe_ipipe_nf));
- if (ipipe_validate_nf_params(nf) < 0) {
- dev_err(dev, "Invalid nf params\n");
- return -EINVAL;
- }
-
-success:
- ipipe_set_d2f_regs(ipipe->base_addr, id, nf);
-
- return 0;
-}
-
-static int ipipe_set_nf1_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- return ipipe_set_nf_params(ipipe, IPIPE_D2F_1ST, param);
-}
-
-static int ipipe_set_nf2_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- return ipipe_set_nf_params(ipipe, IPIPE_D2F_2ND, param);
-}
-
-static int ipipe_get_nf_params(struct vpfe_ipipe_device *ipipe,
- unsigned int id, void *param)
-{
- struct vpfe_ipipe_nf *nf_param = param;
- struct vpfe_ipipe_nf *nf = &ipipe->config.nf1;
-
- if (id == IPIPE_D2F_2ND)
- nf = &ipipe->config.nf2;
-
- memcpy(nf_param, nf, sizeof(struct vpfe_ipipe_nf));
-
- return 0;
-}
-
-static int ipipe_get_nf1_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- return ipipe_get_nf_params(ipipe, IPIPE_D2F_1ST, param);
-}
-
-static int ipipe_get_nf2_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- return ipipe_get_nf_params(ipipe, IPIPE_D2F_2ND, param);
-}
-
-static int ipipe_validate_gic_params(struct vpfe_ipipe_gic *gic)
-{
- if (gic->en > 1 || gic->gain > GIC_GAIN_MASK ||
- gic->thr > GIC_THR_MASK || gic->slope > GIC_SLOPE_MASK ||
- gic->apply_lsc_gain > 1 ||
- gic->nf2_thr_gain.integer > GIC_NFGAN_INT_MASK ||
- gic->nf2_thr_gain.decimal > GIC_NFGAN_DECI_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_gic_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_gic *gic_param = param;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
- struct vpfe_ipipe_gic *gic = &ipipe->config.gic;
-
- if (!gic_param) {
- memset((void *)gic, 0, sizeof(struct vpfe_ipipe_gic));
- goto success;
- }
-
- memcpy(gic, gic_param, sizeof(struct vpfe_ipipe_gic));
- if (ipipe_validate_gic_params(gic) < 0) {
- dev_err(dev, "Invalid gic params\n");
- return -EINVAL;
- }
-
-success:
- ipipe_set_gic_regs(ipipe->base_addr, gic);
-
- return 0;
-}
-
-static int ipipe_get_gic_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_gic *gic_param = param;
- struct vpfe_ipipe_gic *gic = &ipipe->config.gic;
-
- memcpy(gic_param, gic, sizeof(struct vpfe_ipipe_gic));
-
- return 0;
-}
-
-static int ipipe_validate_wb_params(struct vpfe_ipipe_wb *wbal)
-{
- if (wbal->ofst_r > WB_OFFSET_MASK ||
- wbal->ofst_gr > WB_OFFSET_MASK ||
- wbal->ofst_gb > WB_OFFSET_MASK ||
- wbal->ofst_b > WB_OFFSET_MASK ||
- wbal->gain_r.integer > WB_GAIN_INT_MASK ||
- wbal->gain_r.decimal > WB_GAIN_DECI_MASK ||
- wbal->gain_gr.integer > WB_GAIN_INT_MASK ||
- wbal->gain_gr.decimal > WB_GAIN_DECI_MASK ||
- wbal->gain_gb.integer > WB_GAIN_INT_MASK ||
- wbal->gain_gb.decimal > WB_GAIN_DECI_MASK ||
- wbal->gain_b.integer > WB_GAIN_INT_MASK ||
- wbal->gain_b.decimal > WB_GAIN_DECI_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_wb_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_wb *wb_param = param;
- struct vpfe_ipipe_wb *wbal = &ipipe->config.wbal;
-
- if (!wb_param) {
- const struct vpfe_ipipe_wb wb_defaults = {
- .gain_r = {2, 0x0},
- .gain_gr = {2, 0x0},
- .gain_gb = {2, 0x0},
- .gain_b = {2, 0x0}
- };
- memcpy(wbal, &wb_defaults, sizeof(struct vpfe_ipipe_wb));
- goto success;
- }
-
- memcpy(wbal, wb_param, sizeof(struct vpfe_ipipe_wb));
- if (ipipe_validate_wb_params(wbal) < 0)
- return -EINVAL;
-
-success:
- ipipe_set_wb_regs(ipipe->base_addr, wbal);
-
- return 0;
-}
-
-static int ipipe_get_wb_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_wb *wb_param = param;
- struct vpfe_ipipe_wb *wbal = &ipipe->config.wbal;
-
- memcpy(wb_param, wbal, sizeof(struct vpfe_ipipe_wb));
- return 0;
-}
-
-static int ipipe_validate_cfa_params(struct vpfe_ipipe_cfa *cfa)
-{
- if (cfa->hpf_thr_2dir > CFA_HPF_THR_2DIR_MASK ||
- cfa->hpf_slp_2dir > CFA_HPF_SLOPE_2DIR_MASK ||
- cfa->hp_mix_thr_2dir > CFA_HPF_MIX_THR_2DIR_MASK ||
- cfa->hp_mix_slope_2dir > CFA_HPF_MIX_SLP_2DIR_MASK ||
- cfa->dir_thr_2dir > CFA_DIR_THR_2DIR_MASK ||
- cfa->dir_slope_2dir > CFA_DIR_SLP_2DIR_MASK ||
- cfa->nd_wt_2dir > CFA_ND_WT_2DIR_MASK ||
- cfa->hue_fract_daa > CFA_DAA_HUE_FRA_MASK ||
- cfa->edge_thr_daa > CFA_DAA_EDG_THR_MASK ||
- cfa->thr_min_daa > CFA_DAA_THR_MIN_MASK ||
- cfa->thr_slope_daa > CFA_DAA_THR_SLP_MASK ||
- cfa->slope_min_daa > CFA_DAA_SLP_MIN_MASK ||
- cfa->slope_slope_daa > CFA_DAA_SLP_SLP_MASK ||
- cfa->lp_wt_daa > CFA_DAA_LP_WT_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_cfa_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_cfa *cfa_param = param;
- struct vpfe_ipipe_cfa *cfa = &ipipe->config.cfa;
-
- if (!cfa_param) {
- memset(cfa, 0, sizeof(struct vpfe_ipipe_cfa));
- cfa->alg = VPFE_IPIPE_CFA_ALG_2DIRAC;
- goto success;
- }
-
- memcpy(cfa, cfa_param, sizeof(struct vpfe_ipipe_cfa));
- if (ipipe_validate_cfa_params(cfa) < 0)
- return -EINVAL;
-
-success:
- ipipe_set_cfa_regs(ipipe->base_addr, cfa);
-
- return 0;
-}
-
-static int ipipe_get_cfa_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_cfa *cfa_param = param;
- struct vpfe_ipipe_cfa *cfa = &ipipe->config.cfa;
-
- memcpy(cfa_param, cfa, sizeof(struct vpfe_ipipe_cfa));
- return 0;
-}
-
-static int
-ipipe_validate_rgb2rgb_params(struct vpfe_ipipe_rgb2rgb *rgb2rgb,
- unsigned int id)
-{
- u32 gain_int_upper = RGB2RGB_1_GAIN_INT_MASK;
- u32 offset_upper = RGB2RGB_1_OFST_MASK;
-
- if (id == IPIPE_RGB2RGB_2) {
- offset_upper = RGB2RGB_2_OFST_MASK;
- gain_int_upper = RGB2RGB_2_GAIN_INT_MASK;
- }
-
- if (rgb2rgb->coef_rr.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_rr.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->coef_gr.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_gr.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->coef_br.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_br.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->coef_rg.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_rg.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->coef_gg.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_gg.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->coef_bg.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_bg.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->coef_rb.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_rb.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->coef_gb.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_gb.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->coef_bb.decimal > RGB2RGB_GAIN_DECI_MASK ||
- rgb2rgb->coef_bb.integer > gain_int_upper)
- return -EINVAL;
-
- if (rgb2rgb->out_ofst_r > offset_upper ||
- rgb2rgb->out_ofst_g > offset_upper ||
- rgb2rgb->out_ofst_b > offset_upper)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_rgb2rgb_params(struct vpfe_ipipe_device *ipipe,
- unsigned int id, void *param)
-{
- struct vpfe_ipipe_rgb2rgb *rgb2rgb = &ipipe->config.rgb2rgb1;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
- struct vpfe_ipipe_rgb2rgb *rgb2rgb_param;
-
- rgb2rgb_param = param;
-
- if (id == IPIPE_RGB2RGB_2)
- rgb2rgb = &ipipe->config.rgb2rgb2;
-
- if (!rgb2rgb_param) {
- const struct vpfe_ipipe_rgb2rgb rgb2rgb_defaults = {
- .coef_rr = {1, 0}, /* 256 */
- .coef_gr = {0, 0},
- .coef_br = {0, 0},
- .coef_rg = {0, 0},
- .coef_gg = {1, 0}, /* 256 */
- .coef_bg = {0, 0},
- .coef_rb = {0, 0},
- .coef_gb = {0, 0},
- .coef_bb = {1, 0}, /* 256 */
- };
- /* Copy defaults for rgb2rgb conversion */
- memcpy(rgb2rgb, &rgb2rgb_defaults,
- sizeof(struct vpfe_ipipe_rgb2rgb));
- goto success;
- }
-
- memcpy(rgb2rgb, rgb2rgb_param, sizeof(struct vpfe_ipipe_rgb2rgb));
- if (ipipe_validate_rgb2rgb_params(rgb2rgb, id) < 0) {
- dev_err(dev, "Invalid rgb2rgb params\n");
- return -EINVAL;
- }
-
-success:
- ipipe_set_rgb2rgb_regs(ipipe->base_addr, id, rgb2rgb);
-
- return 0;
-}
-
-static int
-ipipe_set_rgb2rgb_1_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- return ipipe_set_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_1, param);
-}
-
-static int
-ipipe_set_rgb2rgb_2_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- return ipipe_set_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_2, param);
-}
-
-static int ipipe_get_rgb2rgb_params(struct vpfe_ipipe_device *ipipe,
- unsigned int id, void *param)
-{
- struct vpfe_ipipe_rgb2rgb *rgb2rgb = &ipipe->config.rgb2rgb1;
- struct vpfe_ipipe_rgb2rgb *rgb2rgb_param;
-
- rgb2rgb_param = param;
-
- if (id == IPIPE_RGB2RGB_2)
- rgb2rgb = &ipipe->config.rgb2rgb2;
-
- memcpy(rgb2rgb_param, rgb2rgb, sizeof(struct vpfe_ipipe_rgb2rgb));
-
- return 0;
-}
-
-static int
-ipipe_get_rgb2rgb_1_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- return ipipe_get_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_1, param);
-}
-
-static int
-ipipe_get_rgb2rgb_2_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- return ipipe_get_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_2, param);
-}
-
-static int
-ipipe_validate_gamma_entry(struct vpfe_ipipe_gamma_entry *table, int size)
-{
- int i;
-
- if (!table)
- return -EINVAL;
-
- for (i = 0; i < size; i++)
- if (table[i].slope > GAMMA_MASK ||
- table[i].offset > GAMMA_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int
-ipipe_validate_gamma_params(struct vpfe_ipipe_gamma *gamma, struct device *dev)
-{
- int table_size;
- int err;
-
- if (gamma->bypass_r > 1 ||
- gamma->bypass_b > 1 ||
- gamma->bypass_g > 1)
- return -EINVAL;
-
- if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM)
- return 0;
-
- table_size = gamma->tbl_size;
- if (!gamma->bypass_r) {
- err = ipipe_validate_gamma_entry(gamma->table_r, table_size);
- if (err) {
- dev_err(dev, "GAMMA R - table entry invalid\n");
- return err;
- }
- }
-
- if (!gamma->bypass_b) {
- err = ipipe_validate_gamma_entry(gamma->table_b, table_size);
- if (err) {
- dev_err(dev, "GAMMA B - table entry invalid\n");
- return err;
- }
- }
-
- if (!gamma->bypass_g) {
- err = ipipe_validate_gamma_entry(gamma->table_g, table_size);
- if (err) {
- dev_err(dev, "GAMMA G - table entry invalid\n");
- return err;
- }
- }
-
- return 0;
-}
-
-static int
-ipipe_set_gamma_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_gamma *gamma_param = param;
- struct vpfe_ipipe_gamma *gamma = &ipipe->config.gamma;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
- int table_size;
-
- if (!gamma_param) {
- memset(gamma, 0, sizeof(struct vpfe_ipipe_gamma));
- gamma->tbl_sel = VPFE_IPIPE_GAMMA_TBL_ROM;
- goto success;
- }
-
- gamma->bypass_r = gamma_param->bypass_r;
- gamma->bypass_b = gamma_param->bypass_b;
- gamma->bypass_g = gamma_param->bypass_g;
- gamma->tbl_sel = gamma_param->tbl_sel;
- gamma->tbl_size = gamma_param->tbl_size;
-
- if (ipipe_validate_gamma_params(gamma, dev) < 0)
- return -EINVAL;
-
- if (gamma_param->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM)
- goto success;
-
- table_size = gamma->tbl_size;
- if (!gamma_param->bypass_r)
- memcpy(&gamma->table_r, &gamma_param->table_r,
- (table_size * sizeof(struct vpfe_ipipe_gamma_entry)));
-
- if (!gamma_param->bypass_b)
- memcpy(&gamma->table_b, &gamma_param->table_b,
- (table_size * sizeof(struct vpfe_ipipe_gamma_entry)));
-
- if (!gamma_param->bypass_g)
- memcpy(&gamma->table_g, &gamma_param->table_g,
- (table_size * sizeof(struct vpfe_ipipe_gamma_entry)));
-
-success:
- ipipe_set_gamma_regs(ipipe->base_addr, ipipe->isp5_base_addr, gamma);
-
- return 0;
-}
-
-static int ipipe_get_gamma_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_gamma *gamma_param = param;
- struct vpfe_ipipe_gamma *gamma = &ipipe->config.gamma;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
- int table_size;
-
- gamma_param->bypass_r = gamma->bypass_r;
- gamma_param->bypass_g = gamma->bypass_g;
- gamma_param->bypass_b = gamma->bypass_b;
- gamma_param->tbl_sel = gamma->tbl_sel;
- gamma_param->tbl_size = gamma->tbl_size;
-
- if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM)
- return 0;
-
- table_size = gamma->tbl_size;
-
- if (!gamma->bypass_r) {
- dev_err(dev,
- "%s: table ptr empty for R\n", __func__);
- return -EINVAL;
- }
- memcpy(gamma_param->table_r, gamma->table_r,
- (table_size * sizeof(struct vpfe_ipipe_gamma_entry)));
-
- if (!gamma->bypass_g) {
- dev_err(dev, "%s: table ptr empty for G\n", __func__);
- return -EINVAL;
- }
- memcpy(gamma_param->table_g, gamma->table_g,
- (table_size * sizeof(struct vpfe_ipipe_gamma_entry)));
-
- if (!gamma->bypass_b) {
- dev_err(dev, "%s: table ptr empty for B\n", __func__);
- return -EINVAL;
- }
- memcpy(gamma_param->table_b, gamma->table_b,
- (table_size * sizeof(struct vpfe_ipipe_gamma_entry)));
-
- return 0;
-}
-
-static int ipipe_validate_3d_lut_params(struct vpfe_ipipe_3d_lut *lut)
-{
- int i;
-
- if (!lut->en)
- return 0;
-
- for (i = 0; i < VPFE_IPIPE_MAX_SIZE_3D_LUT; i++)
- if (lut->table[i].r > D3_LUT_ENTRY_MASK ||
- lut->table[i].g > D3_LUT_ENTRY_MASK ||
- lut->table[i].b > D3_LUT_ENTRY_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_get_3d_lut_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_3d_lut *lut_param = param;
- struct vpfe_ipipe_3d_lut *lut = &ipipe->config.lut;
-
- lut_param->en = lut->en;
-
- memcpy(lut_param->table, &lut->table,
- (VPFE_IPIPE_MAX_SIZE_3D_LUT *
- sizeof(struct vpfe_ipipe_3d_lut_entry)));
-
- return 0;
-}
-
-static int
-ipipe_set_3d_lut_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_3d_lut *lut_param = param;
- struct vpfe_ipipe_3d_lut *lut = &ipipe->config.lut;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
-
- if (!lut_param) {
- memset(lut, 0, sizeof(struct vpfe_ipipe_3d_lut));
- goto success;
- }
-
- memcpy(lut, lut_param, sizeof(struct vpfe_ipipe_3d_lut));
- if (ipipe_validate_3d_lut_params(lut) < 0) {
- dev_err(dev, "Invalid 3D-LUT Params\n");
- return -EINVAL;
- }
-
-success:
- ipipe_set_3d_lut_regs(ipipe->base_addr, ipipe->isp5_base_addr, lut);
-
- return 0;
-}
-
-static int ipipe_validate_rgb2yuv_params(struct vpfe_ipipe_rgb2yuv *rgb2yuv)
-{
- if (rgb2yuv->coef_ry.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_ry.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->coef_gy.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_gy.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->coef_by.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_by.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->coef_rcb.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_rcb.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->coef_gcb.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_gcb.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->coef_bcb.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_bcb.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->coef_rcr.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_rcr.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->coef_gcr.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_gcr.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->coef_bcr.decimal > RGB2YCBCR_COEF_DECI_MASK ||
- rgb2yuv->coef_bcr.integer > RGB2YCBCR_COEF_INT_MASK)
- return -EINVAL;
-
- if (rgb2yuv->out_ofst_y > RGB2YCBCR_OFST_MASK ||
- rgb2yuv->out_ofst_cb > RGB2YCBCR_OFST_MASK ||
- rgb2yuv->out_ofst_cr > RGB2YCBCR_OFST_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int
-ipipe_set_rgb2yuv_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_rgb2yuv *rgb2yuv = &ipipe->config.rgb2yuv;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
- struct vpfe_ipipe_rgb2yuv *rgb2yuv_param;
-
- rgb2yuv_param = param;
- if (!rgb2yuv_param) {
- /* Defaults for rgb2yuv conversion */
- const struct vpfe_ipipe_rgb2yuv rgb2yuv_defaults = {
- .coef_ry = {0, 0x4d},
- .coef_gy = {0, 0x96},
- .coef_by = {0, 0x1d},
- .coef_rcb = {0xf, 0xd5},
- .coef_gcb = {0xf, 0xab},
- .coef_bcb = {0, 0x80},
- .coef_rcr = {0, 0x80},
- .coef_gcr = {0xf, 0x95},
- .coef_bcr = {0xf, 0xeb},
- .out_ofst_cb = 0x80,
- .out_ofst_cr = 0x80,
- };
- /* Copy defaults for rgb2yuv conversion */
- memcpy(rgb2yuv, &rgb2yuv_defaults,
- sizeof(struct vpfe_ipipe_rgb2yuv));
- goto success;
- }
-
- memcpy(rgb2yuv, rgb2yuv_param, sizeof(struct vpfe_ipipe_rgb2yuv));
- if (ipipe_validate_rgb2yuv_params(rgb2yuv) < 0) {
- dev_err(dev, "Invalid rgb2yuv params\n");
- return -EINVAL;
- }
-
-success:
- ipipe_set_rgb2ycbcr_regs(ipipe->base_addr, rgb2yuv);
-
- return 0;
-}
-
-static int
-ipipe_get_rgb2yuv_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_rgb2yuv *rgb2yuv = &ipipe->config.rgb2yuv;
- struct vpfe_ipipe_rgb2yuv *rgb2yuv_param;
-
- rgb2yuv_param = param;
- memcpy(rgb2yuv_param, rgb2yuv, sizeof(struct vpfe_ipipe_rgb2yuv));
- return 0;
-}
-
-static int ipipe_validate_gbce_params(struct vpfe_ipipe_gbce *gbce)
-{
- u32 max = GBCE_Y_VAL_MASK;
- int i;
-
- if (!gbce->en)
- return 0;
-
- if (gbce->type == VPFE_IPIPE_GBCE_GAIN_TBL)
- max = GBCE_GAIN_VAL_MASK;
-
- for (i = 0; i < VPFE_IPIPE_MAX_SIZE_GBCE_LUT; i++)
- if (gbce->table[i] > max)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_gbce_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_gbce *gbce_param = param;
- struct vpfe_ipipe_gbce *gbce = &ipipe->config.gbce;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
-
- if (!gbce_param) {
- memset(gbce, 0, sizeof(struct vpfe_ipipe_gbce));
- } else {
- memcpy(gbce, gbce_param, sizeof(struct vpfe_ipipe_gbce));
- if (ipipe_validate_gbce_params(gbce) < 0) {
- dev_err(dev, "Invalid gbce params\n");
- return -EINVAL;
- }
- }
-
- ipipe_set_gbce_regs(ipipe->base_addr, ipipe->isp5_base_addr, gbce);
-
- return 0;
-}
-
-static int ipipe_get_gbce_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_gbce *gbce_param = param;
- struct vpfe_ipipe_gbce *gbce = &ipipe->config.gbce;
-
- gbce_param->en = gbce->en;
- gbce_param->type = gbce->type;
-
- memcpy(gbce_param->table, gbce->table,
- (VPFE_IPIPE_MAX_SIZE_GBCE_LUT * sizeof(unsigned short)));
-
- return 0;
-}
-
-static int
-ipipe_validate_yuv422_conv_params(struct vpfe_ipipe_yuv422_conv *yuv422_conv)
-{
- if (yuv422_conv->en_chrom_lpf > 1)
- return -EINVAL;
-
- return 0;
-}
-
-static int
-ipipe_set_yuv422_conv_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_yuv422_conv *yuv422_conv = &ipipe->config.yuv422_conv;
- struct vpfe_ipipe_yuv422_conv *yuv422_conv_param;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
-
- yuv422_conv_param = param;
- if (!yuv422_conv_param) {
- memset(yuv422_conv, 0, sizeof(struct vpfe_ipipe_yuv422_conv));
- yuv422_conv->chrom_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE;
- } else {
- memcpy(yuv422_conv, yuv422_conv_param,
- sizeof(struct vpfe_ipipe_yuv422_conv));
- if (ipipe_validate_yuv422_conv_params(yuv422_conv) < 0) {
- dev_err(dev, "Invalid yuv422 params\n");
- return -EINVAL;
- }
- }
-
- ipipe_set_yuv422_conv_regs(ipipe->base_addr, yuv422_conv);
-
- return 0;
-}
-
-static int
-ipipe_get_yuv422_conv_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_yuv422_conv *yuv422_conv = &ipipe->config.yuv422_conv;
- struct vpfe_ipipe_yuv422_conv *yuv422_conv_param;
-
- yuv422_conv_param = param;
- memcpy(yuv422_conv_param, yuv422_conv,
- sizeof(struct vpfe_ipipe_yuv422_conv));
-
- return 0;
-}
-
-static int ipipe_validate_yee_params(struct vpfe_ipipe_yee *yee)
-{
- int i;
-
- if (yee->en > 1 ||
- yee->en_halo_red > 1 ||
- yee->hpf_shft > YEE_HPF_SHIFT_MASK)
- return -EINVAL;
-
- if (yee->hpf_coef_00 > YEE_COEF_MASK ||
- yee->hpf_coef_01 > YEE_COEF_MASK ||
- yee->hpf_coef_02 > YEE_COEF_MASK ||
- yee->hpf_coef_10 > YEE_COEF_MASK ||
- yee->hpf_coef_11 > YEE_COEF_MASK ||
- yee->hpf_coef_12 > YEE_COEF_MASK ||
- yee->hpf_coef_20 > YEE_COEF_MASK ||
- yee->hpf_coef_21 > YEE_COEF_MASK ||
- yee->hpf_coef_22 > YEE_COEF_MASK)
- return -EINVAL;
-
- if (yee->yee_thr > YEE_THR_MASK ||
- yee->es_gain > YEE_ES_GAIN_MASK ||
- yee->es_thr1 > YEE_ES_THR1_MASK ||
- yee->es_thr2 > YEE_THR_MASK ||
- yee->es_gain_grad > YEE_THR_MASK ||
- yee->es_ofst_grad > YEE_THR_MASK)
- return -EINVAL;
-
- for (i = 0; i < VPFE_IPIPE_MAX_SIZE_YEE_LUT; i++)
- if (yee->table[i] > YEE_ENTRY_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_yee_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_yee *yee_param = param;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
- struct vpfe_ipipe_yee *yee = &ipipe->config.yee;
-
- if (!yee_param) {
- memset(yee, 0, sizeof(struct vpfe_ipipe_yee));
- } else {
- memcpy(yee, yee_param, sizeof(struct vpfe_ipipe_yee));
- if (ipipe_validate_yee_params(yee) < 0) {
- dev_err(dev, "Invalid yee params\n");
- return -EINVAL;
- }
- }
-
- ipipe_set_ee_regs(ipipe->base_addr, ipipe->isp5_base_addr, yee);
-
- return 0;
-}
-
-static int ipipe_get_yee_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_yee *yee_param = param;
- struct vpfe_ipipe_yee *yee = &ipipe->config.yee;
-
- yee_param->en = yee->en;
- yee_param->en_halo_red = yee->en_halo_red;
- yee_param->merge_meth = yee->merge_meth;
- yee_param->hpf_shft = yee->hpf_shft;
- yee_param->hpf_coef_00 = yee->hpf_coef_00;
- yee_param->hpf_coef_01 = yee->hpf_coef_01;
- yee_param->hpf_coef_02 = yee->hpf_coef_02;
- yee_param->hpf_coef_10 = yee->hpf_coef_10;
- yee_param->hpf_coef_11 = yee->hpf_coef_11;
- yee_param->hpf_coef_12 = yee->hpf_coef_12;
- yee_param->hpf_coef_20 = yee->hpf_coef_20;
- yee_param->hpf_coef_21 = yee->hpf_coef_21;
- yee_param->hpf_coef_22 = yee->hpf_coef_22;
- yee_param->yee_thr = yee->yee_thr;
- yee_param->es_gain = yee->es_gain;
- yee_param->es_thr1 = yee->es_thr1;
- yee_param->es_thr2 = yee->es_thr2;
- yee_param->es_gain_grad = yee->es_gain_grad;
- yee_param->es_ofst_grad = yee->es_ofst_grad;
- memcpy(yee_param->table, &yee->table,
- (VPFE_IPIPE_MAX_SIZE_YEE_LUT * sizeof(short)));
-
- return 0;
-}
-
-static int ipipe_validate_car_params(struct vpfe_ipipe_car *car)
-{
- if (car->en > 1 || car->hpf_shft > CAR_HPF_SHIFT_MASK ||
- car->gain1.shft > CAR_GAIN1_SHFT_MASK ||
- car->gain1.gain_min > CAR_GAIN_MIN_MASK ||
- car->gain2.shft > CAR_GAIN2_SHFT_MASK ||
- car->gain2.gain_min > CAR_GAIN_MIN_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_car_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_car *car_param = param;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
- struct vpfe_ipipe_car *car = &ipipe->config.car;
-
- if (!car_param) {
- memset(car, 0, sizeof(struct vpfe_ipipe_car));
- } else {
- memcpy(car, car_param, sizeof(struct vpfe_ipipe_car));
- if (ipipe_validate_car_params(car) < 0) {
- dev_err(dev, "Invalid car params\n");
- return -EINVAL;
- }
- }
-
- ipipe_set_car_regs(ipipe->base_addr, car);
-
- return 0;
-}
-
-static int ipipe_get_car_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_car *car_param = param;
- struct vpfe_ipipe_car *car = &ipipe->config.car;
-
- memcpy(car_param, car, sizeof(struct vpfe_ipipe_car));
- return 0;
-}
-
-static int ipipe_validate_cgs_params(struct vpfe_ipipe_cgs *cgs)
-{
- if (cgs->en > 1 || cgs->h_shft > CAR_SHIFT_MASK)
- return -EINVAL;
-
- return 0;
-}
-
-static int ipipe_set_cgs_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_cgs *cgs_param = param;
- struct device *dev = ipipe->subdev.v4l2_dev->dev;
- struct vpfe_ipipe_cgs *cgs = &ipipe->config.cgs;
-
- if (!cgs_param) {
- memset(cgs, 0, sizeof(struct vpfe_ipipe_cgs));
- } else {
- memcpy(cgs, cgs_param, sizeof(struct vpfe_ipipe_cgs));
- if (ipipe_validate_cgs_params(cgs) < 0) {
- dev_err(dev, "Invalid cgs params\n");
- return -EINVAL;
- }
- }
-
- ipipe_set_cgs_regs(ipipe->base_addr, cgs);
-
- return 0;
-}
-
-static int ipipe_get_cgs_params(struct vpfe_ipipe_device *ipipe, void *param)
-{
- struct vpfe_ipipe_cgs *cgs_param = param;
- struct vpfe_ipipe_cgs *cgs = &ipipe->config.cgs;
-
- memcpy(cgs_param, cgs, sizeof(struct vpfe_ipipe_cgs));
-
- return 0;
-}
-
-static const struct ipipe_module_if ipipe_modules[VPFE_IPIPE_MAX_MODULES] = {
- /* VPFE_IPIPE_INPUT_CONFIG */ {
- offsetof(struct ipipe_module_params, input_config),
- FIELD_SIZEOF(struct ipipe_module_params, input_config),
- offsetof(struct vpfe_ipipe_config, input_config),
- ipipe_set_input_config,
- ipipe_get_input_config,
- }, /* VPFE_IPIPE_LUTDPC */ {
- offsetof(struct ipipe_module_params, lutdpc),
- FIELD_SIZEOF(struct ipipe_module_params, lutdpc),
- offsetof(struct vpfe_ipipe_config, lutdpc),
- ipipe_set_lutdpc_params,
- ipipe_get_lutdpc_params,
- }, /* VPFE_IPIPE_OTFDPC */ {
- offsetof(struct ipipe_module_params, otfdpc),
- FIELD_SIZEOF(struct ipipe_module_params, otfdpc),
- offsetof(struct vpfe_ipipe_config, otfdpc),
- ipipe_set_otfdpc_params,
- ipipe_get_otfdpc_params,
- }, /* VPFE_IPIPE_NF1 */ {
- offsetof(struct ipipe_module_params, nf1),
- FIELD_SIZEOF(struct ipipe_module_params, nf1),
- offsetof(struct vpfe_ipipe_config, nf1),
- ipipe_set_nf1_params,
- ipipe_get_nf1_params,
- }, /* VPFE_IPIPE_NF2 */ {
- offsetof(struct ipipe_module_params, nf2),
- FIELD_SIZEOF(struct ipipe_module_params, nf2),
- offsetof(struct vpfe_ipipe_config, nf2),
- ipipe_set_nf2_params,
- ipipe_get_nf2_params,
- }, /* VPFE_IPIPE_WB */ {
- offsetof(struct ipipe_module_params, wbal),
- FIELD_SIZEOF(struct ipipe_module_params, wbal),
- offsetof(struct vpfe_ipipe_config, wbal),
- ipipe_set_wb_params,
- ipipe_get_wb_params,
- }, /* VPFE_IPIPE_RGB2RGB_1 */ {
- offsetof(struct ipipe_module_params, rgb2rgb1),
- FIELD_SIZEOF(struct ipipe_module_params, rgb2rgb1),
- offsetof(struct vpfe_ipipe_config, rgb2rgb1),
- ipipe_set_rgb2rgb_1_params,
- ipipe_get_rgb2rgb_1_params,
- }, /* VPFE_IPIPE_RGB2RGB_2 */ {
- offsetof(struct ipipe_module_params, rgb2rgb2),
- FIELD_SIZEOF(struct ipipe_module_params, rgb2rgb2),
- offsetof(struct vpfe_ipipe_config, rgb2rgb2),
- ipipe_set_rgb2rgb_2_params,
- ipipe_get_rgb2rgb_2_params,
- }, /* VPFE_IPIPE_GAMMA */ {
- offsetof(struct ipipe_module_params, gamma),
- FIELD_SIZEOF(struct ipipe_module_params, gamma),
- offsetof(struct vpfe_ipipe_config, gamma),
- ipipe_set_gamma_params,
- ipipe_get_gamma_params,
- }, /* VPFE_IPIPE_3D_LUT */ {
- offsetof(struct ipipe_module_params, lut),
- FIELD_SIZEOF(struct ipipe_module_params, lut),
- offsetof(struct vpfe_ipipe_config, lut),
- ipipe_set_3d_lut_params,
- ipipe_get_3d_lut_params,
- }, /* VPFE_IPIPE_RGB2YUV */ {
- offsetof(struct ipipe_module_params, rgb2yuv),
- FIELD_SIZEOF(struct ipipe_module_params, rgb2yuv),
- offsetof(struct vpfe_ipipe_config, rgb2yuv),
- ipipe_set_rgb2yuv_params,
- ipipe_get_rgb2yuv_params,
- }, /* VPFE_IPIPE_YUV422_CONV */ {
- offsetof(struct ipipe_module_params, yuv422_conv),
- FIELD_SIZEOF(struct ipipe_module_params, yuv422_conv),
- offsetof(struct vpfe_ipipe_config, yuv422_conv),
- ipipe_set_yuv422_conv_params,
- ipipe_get_yuv422_conv_params,
- }, /* VPFE_IPIPE_YEE */ {
- offsetof(struct ipipe_module_params, yee),
- FIELD_SIZEOF(struct ipipe_module_params, yee),
- offsetof(struct vpfe_ipipe_config, yee),
- ipipe_set_yee_params,
- ipipe_get_yee_params,
- }, /* VPFE_IPIPE_GIC */ {
- offsetof(struct ipipe_module_params, gic),
- FIELD_SIZEOF(struct ipipe_module_params, gic),
- offsetof(struct vpfe_ipipe_config, gic),
- ipipe_set_gic_params,
- ipipe_get_gic_params,
- }, /* VPFE_IPIPE_CFA */ {
- offsetof(struct ipipe_module_params, cfa),
- FIELD_SIZEOF(struct ipipe_module_params, cfa),
- offsetof(struct vpfe_ipipe_config, cfa),
- ipipe_set_cfa_params,
- ipipe_get_cfa_params,
- }, /* VPFE_IPIPE_CAR */ {
- offsetof(struct ipipe_module_params, car),
- FIELD_SIZEOF(struct ipipe_module_params, car),
- offsetof(struct vpfe_ipipe_config, car),
- ipipe_set_car_params,
- ipipe_get_car_params,
- }, /* VPFE_IPIPE_CGS */ {
- offsetof(struct ipipe_module_params, cgs),
- FIELD_SIZEOF(struct ipipe_module_params, cgs),
- offsetof(struct vpfe_ipipe_config, cgs),
- ipipe_set_cgs_params,
- ipipe_get_cgs_params,
- }, /* VPFE_IPIPE_GBCE */ {
- offsetof(struct ipipe_module_params, gbce),
- FIELD_SIZEOF(struct ipipe_module_params, gbce),
- offsetof(struct vpfe_ipipe_config, gbce),
- ipipe_set_gbce_params,
- ipipe_get_gbce_params,
- },
-};
-
-static int ipipe_s_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg)
-{
- struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
- unsigned int i;
- int rval = 0;
- struct ipipe_module_params *params;
-
- for (i = 0; i < ARRAY_SIZE(ipipe_modules); i++) {
- const struct ipipe_module_if *module_if;
- void *from, *to;
- size_t size;
-
- if (!(cfg->flag & BIT(i)))
- continue;
-
- module_if = &ipipe_modules[i];
- from = *(void **)((void *)cfg + module_if->config_offset);
-
- params = kmalloc(sizeof(*params), GFP_KERNEL);
- if (!params)
- return -ENOMEM;
- to = (void *)params + module_if->param_offset;
- size = module_if->param_size;
-
- if (to && from && size) {
- if (copy_from_user(to, (void __user *)from, size)) {
- rval = -EFAULT;
- goto error_free;
- }
- rval = module_if->set(ipipe, to);
- if (rval)
- goto error_free;
- } else if (to && !from && size) {
- rval = module_if->set(ipipe, NULL);
- if (rval)
- goto error_free;
- }
- kfree(params);
- }
- return rval;
-
-error_free:
- kfree(params);
- return rval;
-}
-
-static int ipipe_g_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg)
-{
- struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
- unsigned int i;
- int rval = 0;
-
- for (i = 1; i < ARRAY_SIZE(ipipe_modules); i++) {
- const struct ipipe_module_if *module_if;
- struct ipipe_module_params *params;
- void *from, *to;
- size_t size;
-
- if (!(cfg->flag & BIT(i)))
- continue;
-
- module_if = &ipipe_modules[i];
- to = *(void **)((void *)cfg + module_if->config_offset);
-
- params = kmalloc(sizeof(*params), GFP_KERNEL);
- from = (void *)params + module_if->param_offset;
- size = module_if->param_size;
-
- if (to && from && size) {
- rval = module_if->get(ipipe, from);
- if (rval)
- goto error;
- if (copy_to_user((void __user *)to, from, size)) {
- rval = -EFAULT;
- break;
- }
- }
- kfree(params);
- }
-error:
- return rval;
-}
-
-/*
- * ipipe_ioctl() - Handle ipipe module private ioctl's
- * @sd: pointer to v4l2 subdev structure
- * @cmd: configuration command
- * @arg: configuration argument
- */
-static long ipipe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case VIDIOC_VPFE_IPIPE_S_CONFIG:
- return ipipe_s_config(sd, arg);
-
- case VIDIOC_VPFE_IPIPE_G_CONFIG:
- return ipipe_g_config(sd, arg);
-
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-void vpfe_ipipe_enable(struct vpfe_device *vpfe_dev, int en)
-{
- struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
- struct vpfe_ipipe_device *ipipe = &vpfe_dev->vpfe_ipipe;
- unsigned char val;
-
- if (ipipe->input == IPIPE_INPUT_NONE)
- return;
-
- /* ipipe is set to single shot */
- if (ipipeif->input == IPIPEIF_INPUT_MEMORY && en) {
- /* for single-shot mode, need to wait for h/w to
- * reset many register bits
- */
- do {
- val = regr_ip(vpfe_dev->vpfe_ipipe.base_addr,
- IPIPE_SRC_EN);
- } while (val);
- }
- regw_ip(vpfe_dev->vpfe_ipipe.base_addr, en, IPIPE_SRC_EN);
-}
-
-/*
- * ipipe_set_stream() - Enable/Disable streaming on the ipipe subdevice
- * @sd: pointer to v4l2 subdev structure
- * @enable: 1 == Enable, 0 == Disable
- */
-static int ipipe_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
- struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe);
-
- if (enable && ipipe->input != IPIPE_INPUT_NONE &&
- ipipe->output != IPIPE_OUTPUT_NONE) {
- if (config_ipipe_hw(ipipe) < 0)
- return -EINVAL;
- }
-
- vpfe_ipipe_enable(vpfe_dev, enable);
-
- return 0;
-}
-
-/*
- * __ipipe_get_format() - helper function for getting ipipe format
- * @ipipe: pointer to ipipe private structure.
- * @pad: pad number.
- * @cfg: V4L2 subdev pad config
- * @which: wanted subdev format.
- *
- */
-static struct v4l2_mbus_framefmt *
-__ipipe_get_format(struct vpfe_ipipe_device *ipipe,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad);
-
- return &ipipe->formats[pad];
-}
-
-/*
- * ipipe_try_format() - Handle try format by pad subdev method
- * @ipipe: VPFE ipipe device.
- * @cfg: V4L2 subdev pad config
- * @pad: pad num.
- * @fmt: pointer to v4l2 format structure.
- * @which : wanted subdev format
- */
-static void
-ipipe_try_format(struct vpfe_ipipe_device *ipipe,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
- struct v4l2_mbus_framefmt *fmt,
- enum v4l2_subdev_format_whence which)
-{
- unsigned int max_out_height;
- unsigned int max_out_width;
- unsigned int i;
-
- max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
- max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
-
- if (pad == IPIPE_PAD_SINK) {
- for (i = 0; i < ARRAY_SIZE(ipipe_input_fmts); i++)
- if (fmt->code == ipipe_input_fmts[i])
- break;
-
- /* If not found, use SBGGR10 as default */
- if (i >= ARRAY_SIZE(ipipe_input_fmts))
- fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12;
- } else if (pad == IPIPE_PAD_SOURCE) {
- for (i = 0; i < ARRAY_SIZE(ipipe_output_fmts); i++)
- if (fmt->code == ipipe_output_fmts[i])
- break;
-
- /* If not found, use UYVY as default */
- if (i >= ARRAY_SIZE(ipipe_output_fmts))
- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
- }
-
- fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
- fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height);
-}
-
-/*
- * ipipe_set_format() - Handle set format by pads subdev method
- * @sd: pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int
-ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which);
- if (!format)
- return -EINVAL;
-
- ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- return 0;
-
- if (fmt->pad == IPIPE_PAD_SINK &&
- (ipipe->input == IPIPE_INPUT_CCDC ||
- ipipe->input == IPIPE_INPUT_MEMORY))
- ipipe->formats[fmt->pad] = fmt->format;
- else if (fmt->pad == IPIPE_PAD_SOURCE &&
- ipipe->output == IPIPE_OUTPUT_RESIZER)
- ipipe->formats[fmt->pad] = fmt->format;
- else
- return -EINVAL;
-
- return 0;
-}
-
-/*
- * ipipe_get_format() - Handle get format by pads subdev method.
- * @sd: pointer to v4l2 subdev structure.
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure.
- */
-static int
-ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- fmt->format = ipipe->formats[fmt->pad];
- else
- fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad));
-
- return 0;
-}
-
-/*
- * ipipe_enum_frame_size() - enum frame sizes on pads
- * @sd: pointer to v4l2 subdev structure.
- * @cfg: V4L2 subdev pad config
- * @fse: pointer to v4l2_subdev_frame_size_enum structure.
- */
-static int
-ipipe_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt format;
-
- if (fse->index != 0)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = 1;
- format.height = 1;
- ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which);
- fse->min_width = format.width;
- fse->min_height = format.height;
-
- if (format.code != fse->code)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = -1;
- format.height = -1;
- ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which);
- fse->max_width = format.width;
- fse->max_height = format.height;
-
- return 0;
-}
-
-/*
- * ipipe_enum_mbus_code() - enum mbus codes for pads
- * @sd: pointer to v4l2 subdev structure.
- * @cfg: V4L2 subdev pad config
- * @code: pointer to v4l2_subdev_mbus_code_enum structure
- */
-static int
-ipipe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- switch (code->pad) {
- case IPIPE_PAD_SINK:
- if (code->index >= ARRAY_SIZE(ipipe_input_fmts))
- return -EINVAL;
- code->code = ipipe_input_fmts[code->index];
- break;
-
- case IPIPE_PAD_SOURCE:
- if (code->index >= ARRAY_SIZE(ipipe_output_fmts))
- return -EINVAL;
- code->code = ipipe_output_fmts[code->index];
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * ipipe_s_ctrl() - Handle set control subdev method
- * @ctrl: pointer to v4l2 control structure
- */
-static int ipipe_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct vpfe_ipipe_device *ipipe =
- container_of(ctrl->handler, struct vpfe_ipipe_device, ctrls);
- struct ipipe_lum_adj *lum_adj = &ipipe->config.lum_adj;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- lum_adj->brightness = ctrl->val;
- ipipe_set_lum_adj_regs(ipipe->base_addr, lum_adj);
- break;
-
- case V4L2_CID_CONTRAST:
- lum_adj->contrast = ctrl->val;
- ipipe_set_lum_adj_regs(ipipe->base_addr, lum_adj);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * ipipe_init_formats() - Initialize formats on all pads
- * @sd: pointer to v4l2 subdev structure.
- * @fh: V4L2 subdev file handle
- *
- * Initialize all pad formats with default values. Try formats are initialized
- * on the file handle.
- */
-static int
-ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_subdev_format format;
-
- memset(&format, 0, sizeof(format));
- format.pad = IPIPE_PAD_SINK;
- format.which = V4L2_SUBDEV_FORMAT_TRY;
- format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
- format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
- format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
- ipipe_set_format(sd, fh->pad, &format);
-
- memset(&format, 0, sizeof(format));
- format.pad = IPIPE_PAD_SOURCE;
- format.which = V4L2_SUBDEV_FORMAT_TRY;
- format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
- format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
- format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
- ipipe_set_format(sd, fh->pad, &format);
-
- return 0;
-}
-
-/* subdev core operations */
-static const struct v4l2_subdev_core_ops ipipe_v4l2_core_ops = {
- .ioctl = ipipe_ioctl,
-};
-
-static const struct v4l2_ctrl_ops ipipe_ctrl_ops = {
- .s_ctrl = ipipe_s_ctrl,
-};
-
-/* subdev file operations */
-static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = {
- .open = ipipe_init_formats,
-};
-
-/* subdev video operations */
-static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = {
- .s_stream = ipipe_set_stream,
-};
-
-/* subdev pad operations */
-static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = {
- .enum_mbus_code = ipipe_enum_mbus_code,
- .enum_frame_size = ipipe_enum_frame_size,
- .get_fmt = ipipe_get_format,
- .set_fmt = ipipe_set_format,
-};
-
-/* v4l2 subdev operation */
-static const struct v4l2_subdev_ops ipipe_v4l2_ops = {
- .core = &ipipe_v4l2_core_ops,
- .video = &ipipe_v4l2_video_ops,
- .pad = &ipipe_v4l2_pad_ops,
-};
-
-/*
- * Media entity operations
- */
-
-/*
- * ipipe_link_setup() - Setup ipipe connections
- * @entity: ipipe media entity
- * @local: Pad at the local end of the link
- * @remote: Pad at the remote end of the link
- * @flags: Link flags
- *
- * return -EINVAL or zero on success
- */
-static int
-ipipe_link_setup(struct media_entity *entity, const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
- struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe);
- u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
-
- if (!is_media_entity_v4l2_subdev(remote->entity))
- return -EINVAL;
-
- switch (local->index) {
- case IPIPE_PAD_SINK:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- ipipe->input = IPIPE_INPUT_NONE;
- break;
- }
- if (ipipe->input != IPIPE_INPUT_NONE)
- return -EBUSY;
- if (ipipeif_sink == IPIPEIF_INPUT_MEMORY)
- ipipe->input = IPIPE_INPUT_MEMORY;
- else
- ipipe->input = IPIPE_INPUT_CCDC;
- break;
-
- case IPIPE_PAD_SOURCE:
- /* out to RESIZER */
- if (flags & MEDIA_LNK_FL_ENABLED)
- ipipe->output = IPIPE_OUTPUT_RESIZER;
- else
- ipipe->output = IPIPE_OUTPUT_NONE;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const struct media_entity_operations ipipe_media_ops = {
- .link_setup = ipipe_link_setup,
-};
-
-/*
- * vpfe_ipipe_unregister_entities() - ipipe unregister entity
- * @vpfe_ipipe: pointer to ipipe subdevice structure.
- */
-void vpfe_ipipe_unregister_entities(struct vpfe_ipipe_device *vpfe_ipipe)
-{
- /* unregister subdev */
- v4l2_device_unregister_subdev(&vpfe_ipipe->subdev);
- /* cleanup entity */
- media_entity_cleanup(&vpfe_ipipe->subdev.entity);
-}
-
-/*
- * vpfe_ipipe_register_entities() - ipipe register entity
- * @ipipe: pointer to ipipe subdevice structure.
- * @vdev: pointer to v4l2 device structure.
- */
-int
-vpfe_ipipe_register_entities(struct vpfe_ipipe_device *ipipe,
- struct v4l2_device *vdev)
-{
- int ret;
-
- /* Register the subdev */
- ret = v4l2_device_register_subdev(vdev, &ipipe->subdev);
- if (ret) {
- pr_err("Failed to register ipipe as v4l2 subdevice\n");
- return ret;
- }
-
- return ret;
-}
-
-#define IPIPE_CONTRAST_HIGH 0xff
-#define IPIPE_BRIGHT_HIGH 0xff
-
-/*
- * vpfe_ipipe_init() - ipipe module initialization.
- * @ipipe: pointer to ipipe subdevice structure.
- * @pdev: platform device pointer.
- */
-int
-vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev)
-{
- struct media_pad *pads = &ipipe->pads[0];
- struct v4l2_subdev *sd = &ipipe->subdev;
- struct media_entity *me = &sd->entity;
- struct resource *res, *res2, *memres;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
- if (!res)
- return -ENOENT;
-
- memres = request_mem_region(res->start, resource_size(res), res->name);
- if (!memres)
- return -EBUSY;
- ipipe->base_addr = ioremap_nocache(memres->start,
- resource_size(memres));
- if (!ipipe->base_addr)
- goto error_release;
-
- res2 = platform_get_resource(pdev, IORESOURCE_MEM, 6);
- if (!res2)
- goto error_unmap;
- ipipe->isp5_base_addr = ioremap_nocache(res2->start,
- resource_size(res2));
- if (!ipipe->isp5_base_addr)
- goto error_unmap;
-
- v4l2_subdev_init(sd, &ipipe_v4l2_ops);
- sd->internal_ops = &ipipe_v4l2_internal_ops;
- strscpy(sd->name, "DAVINCI IPIPE", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
- v4l2_set_subdevdata(sd, ipipe);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[IPIPE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-
- ipipe->input = IPIPE_INPUT_NONE;
- ipipe->output = IPIPE_OUTPUT_NONE;
-
- me->ops = &ipipe_media_ops;
- v4l2_ctrl_handler_init(&ipipe->ctrls, 2);
- v4l2_ctrl_new_std(&ipipe->ctrls, &ipipe_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0,
- IPIPE_BRIGHT_HIGH, 1, 16);
- v4l2_ctrl_new_std(&ipipe->ctrls, &ipipe_ctrl_ops,
- V4L2_CID_CONTRAST, 0,
- IPIPE_CONTRAST_HIGH, 1, 16);
- v4l2_ctrl_handler_setup(&ipipe->ctrls);
- sd->ctrl_handler = &ipipe->ctrls;
-
- return media_entity_pads_init(me, IPIPE_PADS_NUM, pads);
-
-error_unmap:
- iounmap(ipipe->base_addr);
-error_release:
- release_mem_region(memres->start, resource_size(memres));
- return -ENOMEM;
-}
-
-/*
- * vpfe_ipipe_cleanup() - ipipe subdevice cleanup.
- * @ipipe: pointer to ipipe subdevice
- * @dev: pointer to platform device
- */
-void vpfe_ipipe_cleanup(struct vpfe_ipipe_device *ipipe,
- struct platform_device *pdev)
-{
- struct resource *res;
-
- v4l2_ctrl_handler_free(&ipipe->ctrls);
-
- iounmap(ipipe->base_addr);
- iounmap(ipipe->isp5_base_addr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
- if (res)
- release_mem_region(res->start, resource_size(res));
-}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.h b/drivers/staging/media/davinci_vpfe/dm365_ipipe.h
deleted file mode 100644
index 866ae12aeb07..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_DM365_IPIPE_H
-#define _DAVINCI_VPFE_DM365_IPIPE_H
-
-#include <linux/platform_device.h>
-
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-subdev.h>
-
-#include "davinci_vpfe_user.h"
-#include "vpfe_video.h"
-
-enum ipipe_noise_filter {
- IPIPE_D2F_1ST = 0,
- IPIPE_D2F_2ND = 1,
-};
-
-/* Used for driver storage */
-struct ipipe_otfdpc_2_0 {
- /* 0 - disable, 1 - enable */
- unsigned char en;
- /* defect detection method */
- enum vpfe_ipipe_otfdpc_det_meth det_method;
- /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is
- * used
- */
- enum vpfe_ipipe_otfdpc_alg alg;
- struct vpfe_ipipe_otfdpc_2_0_cfg otfdpc_2_0;
-};
-
-struct ipipe_otfdpc_3_0 {
- /* 0 - disable, 1 - enable */
- unsigned char en;
- /* defect detection method */
- enum vpfe_ipipe_otfdpc_det_meth det_method;
- /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is
- * used
- */
- enum vpfe_ipipe_otfdpc_alg alg;
- struct vpfe_ipipe_otfdpc_3_0_cfg otfdpc_3_0;
-};
-
-/* Structure for configuring Luminance Adjustment module */
-struct ipipe_lum_adj {
- /* Brightness adjustments */
- unsigned char brightness;
- /* contrast adjustments */
- unsigned char contrast;
-};
-
-enum ipipe_rgb2rgb {
- IPIPE_RGB2RGB_1 = 0,
- IPIPE_RGB2RGB_2 = 1,
-};
-
-struct ipipe_module_params {
- __u32 flag;
- struct vpfe_ipipe_input_config input_config;
- struct vpfe_ipipe_lutdpc lutdpc;
- struct vpfe_ipipe_otfdpc otfdpc;
- struct vpfe_ipipe_nf nf1;
- struct vpfe_ipipe_nf nf2;
- struct vpfe_ipipe_gic gic;
- struct vpfe_ipipe_wb wbal;
- struct vpfe_ipipe_cfa cfa;
- struct vpfe_ipipe_rgb2rgb rgb2rgb1;
- struct vpfe_ipipe_rgb2rgb rgb2rgb2;
- struct vpfe_ipipe_gamma gamma;
- struct vpfe_ipipe_3d_lut lut;
- struct vpfe_ipipe_rgb2yuv rgb2yuv;
- struct vpfe_ipipe_gbce gbce;
- struct vpfe_ipipe_yuv422_conv yuv422_conv;
- struct vpfe_ipipe_yee yee;
- struct vpfe_ipipe_car car;
- struct vpfe_ipipe_cgs cgs;
- struct ipipe_lum_adj lum_adj;
-};
-
-#define IPIPE_PAD_SINK 0
-#define IPIPE_PAD_SOURCE 1
-
-#define IPIPE_PADS_NUM 2
-
-#define IPIPE_OUTPUT_NONE 0
-#define IPIPE_OUTPUT_RESIZER (1 << 0)
-
-enum ipipe_input_entity {
- IPIPE_INPUT_NONE = 0,
- IPIPE_INPUT_MEMORY = 1,
- IPIPE_INPUT_CCDC = 2,
-};
-
-
-struct vpfe_ipipe_device {
- struct v4l2_subdev subdev;
- struct media_pad pads[IPIPE_PADS_NUM];
- struct v4l2_mbus_framefmt formats[IPIPE_PADS_NUM];
- enum ipipe_input_entity input;
- unsigned int output;
- struct v4l2_ctrl_handler ctrls;
- void __iomem *base_addr;
- void __iomem *isp5_base_addr;
- struct ipipe_module_params config;
-};
-
-struct ipipe_module_if {
- unsigned int param_offset;
- unsigned int param_size;
- unsigned int config_offset;
- int (*set)(struct vpfe_ipipe_device *ipipe, void *param);
- int (*get)(struct vpfe_ipipe_device *ipipe, void *param);
-};
-
-/* data paths */
-enum ipipe_data_paths {
- IPIPE_RAW2YUV,
- /* Bayer RAW input to YCbCr output */
- IPIPE_RAW2RAW,
- /* Bayer Raw to Bayer output */
- IPIPE_RAW2BOX,
- /* Bayer Raw to Boxcar output */
- IPIPE_YUV2YUV
- /* YUV Raw to YUV Raw output */
-};
-
-#define IPIPE_COLPTN_R_Ye 0x0
-#define IPIPE_COLPTN_Gr_Cy 0x1
-#define IPIPE_COLPTN_Gb_G 0x2
-#define IPIPE_COLPTN_B_Mg 0x3
-
-#define COLPAT_EE_SHIFT 0
-#define COLPAT_EO_SHIFT 2
-#define COLPAT_OE_SHIFT 4
-#define COLPAT_OO_SHIFT 6
-
-#define ipipe_sgrbg_pattern \
- (IPIPE_COLPTN_Gr_Cy << COLPAT_EE_SHIFT | \
- IPIPE_COLPTN_R_Ye << COLPAT_EO_SHIFT | \
- IPIPE_COLPTN_B_Mg << COLPAT_OE_SHIFT | \
- IPIPE_COLPTN_Gb_G << COLPAT_OO_SHIFT)
-
-#define ipipe_srggb_pattern \
- (IPIPE_COLPTN_R_Ye << COLPAT_EE_SHIFT | \
- IPIPE_COLPTN_Gr_Cy << COLPAT_EO_SHIFT | \
- IPIPE_COLPTN_Gb_G << COLPAT_OE_SHIFT | \
- IPIPE_COLPTN_B_Mg << COLPAT_OO_SHIFT)
-
-int vpfe_ipipe_register_entities(struct vpfe_ipipe_device *ipipe,
- struct v4l2_device *v4l2_dev);
-int vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe,
- struct platform_device *pdev);
-void vpfe_ipipe_unregister_entities(struct vpfe_ipipe_device *ipipe);
-void vpfe_ipipe_cleanup(struct vpfe_ipipe_device *ipipe,
- struct platform_device *pdev);
-void vpfe_ipipe_enable(struct vpfe_device *vpfe_dev, int en);
-
-#endif /* _DAVINCI_VPFE_DM365_IPIPE_H */
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
deleted file mode 100644
index 110473c30577..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
+++ /dev/null
@@ -1,1038 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#include "dm365_ipipe_hw.h"
-
-#define IPIPE_MODE_CONTINUOUS 0
-#define IPIPE_MODE_SINGLE_SHOT 1
-
-static void ipipe_clock_enable(void __iomem *base_addr)
-{
- /* enable IPIPE MMR for register write access */
- regw_ip(base_addr, IPIPE_GCK_MMR_DEFAULT, IPIPE_GCK_MMR);
-
- /* enable the clock wb,cfa,dfc,d2f,pre modules */
- regw_ip(base_addr, IPIPE_GCK_PIX_DEFAULT, IPIPE_GCK_PIX);
-}
-
-static void
-rsz_set_common_params(void __iomem *rsz_base, struct resizer_params *params)
-{
- struct rsz_common_params *rsz_common = &params->rsz_common;
- u32 val;
-
- /* Set mode */
- regw_rsz(rsz_base, params->oper_mode, RSZ_SRC_MODE);
-
- /* data source selection and bypass */
- val = (rsz_common->passthrough << RSZ_BYPASS_SHIFT) |
- rsz_common->source;
- regw_rsz(rsz_base, val, RSZ_SRC_FMT0);
-
- /* src image selection */
- val = (rsz_common->raw_flip & 1) |
- (rsz_common->src_img_fmt << RSZ_SRC_IMG_FMT_SHIFT) |
- ((rsz_common->y_c & 1) << RSZ_SRC_Y_C_SEL_SHIFT);
- regw_rsz(rsz_base, val, RSZ_SRC_FMT1);
-
- regw_rsz(rsz_base, rsz_common->vps & IPIPE_RSZ_VPS_MASK, RSZ_SRC_VPS);
- regw_rsz(rsz_base, rsz_common->hps & IPIPE_RSZ_HPS_MASK, RSZ_SRC_HPS);
- regw_rsz(rsz_base, rsz_common->vsz & IPIPE_RSZ_VSZ_MASK, RSZ_SRC_VSZ);
- regw_rsz(rsz_base, rsz_common->hsz & IPIPE_RSZ_HSZ_MASK, RSZ_SRC_HSZ);
- regw_rsz(rsz_base, rsz_common->yuv_y_min, RSZ_YUV_Y_MIN);
- regw_rsz(rsz_base, rsz_common->yuv_y_max, RSZ_YUV_Y_MAX);
- regw_rsz(rsz_base, rsz_common->yuv_c_min, RSZ_YUV_C_MIN);
- regw_rsz(rsz_base, rsz_common->yuv_c_max, RSZ_YUV_C_MAX);
- /* chromatic position */
- regw_rsz(rsz_base, rsz_common->out_chr_pos, RSZ_YUV_PHS);
-}
-
-static void
-rsz_set_rsz_regs(void __iomem *rsz_base, unsigned int rsz_id,
- struct resizer_params *params)
-{
- struct resizer_scale_param *rsc_params;
- struct rsz_ext_mem_param *ext_mem;
- struct resizer_rgb *rgb;
- u32 reg_base;
- u32 val;
-
- rsc_params = &params->rsz_rsc_param[rsz_id];
- rgb = &params->rsz2rgb[rsz_id];
- ext_mem = &params->ext_mem_param[rsz_id];
-
- if (rsz_id == RSZ_A) {
- val = rsc_params->h_flip << RSZA_H_FLIP_SHIFT;
- val |= rsc_params->v_flip << RSZA_V_FLIP_SHIFT;
- reg_base = RSZ_EN_A;
- } else {
- val = rsc_params->h_flip << RSZB_H_FLIP_SHIFT;
- val |= rsc_params->v_flip << RSZB_V_FLIP_SHIFT;
- reg_base = RSZ_EN_B;
- }
- /* update flip settings */
- regw_rsz(rsz_base, val, RSZ_SEQ);
-
- regw_rsz(rsz_base, params->oper_mode, reg_base + RSZ_MODE);
-
- val = (rsc_params->cen << RSZ_CEN_SHIFT) | rsc_params->yen;
- regw_rsz(rsz_base, val, reg_base + RSZ_420);
-
- regw_rsz(rsz_base, rsc_params->i_vps & RSZ_VPS_MASK,
- reg_base + RSZ_I_VPS);
- regw_rsz(rsz_base, rsc_params->i_hps & RSZ_HPS_MASK,
- reg_base + RSZ_I_HPS);
- regw_rsz(rsz_base, rsc_params->o_vsz & RSZ_O_VSZ_MASK,
- reg_base + RSZ_O_VSZ);
- regw_rsz(rsz_base, rsc_params->o_hsz & RSZ_O_HSZ_MASK,
- reg_base + RSZ_O_HSZ);
- regw_rsz(rsz_base, rsc_params->v_phs_y & RSZ_V_PHS_MASK,
- reg_base + RSZ_V_PHS_Y);
- regw_rsz(rsz_base, rsc_params->v_phs_c & RSZ_V_PHS_MASK,
- reg_base + RSZ_V_PHS_C);
-
- /* keep this additional adjustment to zero for now */
- regw_rsz(rsz_base, rsc_params->v_dif & RSZ_V_DIF_MASK,
- reg_base + RSZ_V_DIF);
-
- val = (rsc_params->v_typ_y & 1) |
- ((rsc_params->v_typ_c & 1) << RSZ_TYP_C_SHIFT);
- regw_rsz(rsz_base, val, reg_base + RSZ_V_TYP);
-
- val = (rsc_params->v_lpf_int_y & RSZ_LPF_INT_MASK) |
- ((rsc_params->v_lpf_int_c & RSZ_LPF_INT_MASK) <<
- RSZ_LPF_INT_C_SHIFT);
- regw_rsz(rsz_base, val, reg_base + RSZ_V_LPF);
-
- regw_rsz(rsz_base, rsc_params->h_phs &
- RSZ_H_PHS_MASK, reg_base + RSZ_H_PHS);
-
- regw_rsz(rsz_base, 0, reg_base + RSZ_H_PHS_ADJ);
- regw_rsz(rsz_base, rsc_params->h_dif &
- RSZ_H_DIF_MASK, reg_base + RSZ_H_DIF);
-
- val = (rsc_params->h_typ_y & 1) |
- ((rsc_params->h_typ_c & 1) << RSZ_TYP_C_SHIFT);
- regw_rsz(rsz_base, val, reg_base + RSZ_H_TYP);
-
- val = (rsc_params->h_lpf_int_y & RSZ_LPF_INT_MASK) |
- ((rsc_params->h_lpf_int_c & RSZ_LPF_INT_MASK) <<
- RSZ_LPF_INT_C_SHIFT);
- regw_rsz(rsz_base, val, reg_base + RSZ_H_LPF);
-
- regw_rsz(rsz_base, rsc_params->dscale_en & 1, reg_base + RSZ_DWN_EN);
-
- val = (rsc_params->h_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) |
- ((rsc_params->v_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) <<
- RSZ_DWN_SCALE_AV_SZ_V_SHIFT);
- regw_rsz(rsz_base, val, reg_base + RSZ_DWN_AV);
-
- /* setting rgb conversion parameters */
- regw_rsz(rsz_base, rgb->rgb_en, reg_base + RSZ_RGB_EN);
-
- val = (rgb->rgb_typ << RSZ_RGB_TYP_SHIFT) |
- (rgb->rgb_msk0 << RSZ_RGB_MSK0_SHIFT) |
- (rgb->rgb_msk1 << RSZ_RGB_MSK1_SHIFT);
- regw_rsz(rsz_base, val, reg_base + RSZ_RGB_TYP);
-
- regw_rsz(rsz_base, rgb->rgb_alpha_val & RSZ_RGB_ALPHA_MASK,
- reg_base + RSZ_RGB_BLD);
-
- /* setting external memory parameters */
- regw_rsz(rsz_base, ext_mem->rsz_sdr_oft_y, reg_base + RSZ_SDR_Y_OFT);
- regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_s_y,
- reg_base + RSZ_SDR_Y_PTR_S);
- regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_e_y,
- reg_base + RSZ_SDR_Y_PTR_E);
- regw_rsz(rsz_base, ext_mem->rsz_sdr_oft_c, reg_base + RSZ_SDR_C_OFT);
- regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_s_c,
- reg_base + RSZ_SDR_C_PTR_S);
- regw_rsz(rsz_base, (ext_mem->rsz_sdr_ptr_e_c >> 1),
- reg_base + RSZ_SDR_C_PTR_E);
-}
-
-/*set the registers of either RSZ0 or RSZ1 */
-static void
-ipipe_setup_resizer(void __iomem *rsz_base, struct resizer_params *params)
-{
- /* enable MMR gate to write to Resizer */
- regw_rsz(rsz_base, 1, RSZ_GCK_MMR);
-
- /* Enable resizer if it is not in bypass mode */
- if (params->rsz_common.passthrough)
- regw_rsz(rsz_base, 0, RSZ_GCK_SDR);
- else
- regw_rsz(rsz_base, 1, RSZ_GCK_SDR);
-
- rsz_set_common_params(rsz_base, params);
-
- regw_rsz(rsz_base, params->rsz_en[RSZ_A], RSZ_EN_A);
-
- if (params->rsz_en[RSZ_A])
- /*setting rescale parameters */
- rsz_set_rsz_regs(rsz_base, RSZ_A, params);
-
- regw_rsz(rsz_base, params->rsz_en[RSZ_B], RSZ_EN_B);
-
- if (params->rsz_en[RSZ_B])
- rsz_set_rsz_regs(rsz_base, RSZ_B, params);
-}
-
-static u32 ipipe_get_color_pat(u32 pix)
-{
- switch (pix) {
- case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
- case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
- case MEDIA_BUS_FMT_SGRBG12_1X12:
- return ipipe_sgrbg_pattern;
-
- default:
- return ipipe_srggb_pattern;
- }
-}
-
-static int ipipe_get_data_path(struct vpfe_ipipe_device *ipipe)
-{
- u32 temp_pix_fmt;
-
- switch (ipipe->formats[IPIPE_PAD_SINK].code) {
- case MEDIA_BUS_FMT_SBGGR8_1X8:
- case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
- case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
- case MEDIA_BUS_FMT_SGRBG12_1X12:
- temp_pix_fmt = MEDIA_BUS_FMT_SGRBG12_1X12;
- break;
-
- default:
- temp_pix_fmt = MEDIA_BUS_FMT_UYVY8_2X8;
- }
-
- if (temp_pix_fmt == MEDIA_BUS_FMT_SGRBG12_1X12) {
- if (ipipe->formats[IPIPE_PAD_SOURCE].code ==
- MEDIA_BUS_FMT_SGRBG12_1X12)
- return IPIPE_RAW2RAW;
- return IPIPE_RAW2YUV;
- }
-
- return IPIPE_YUV2YUV;
-}
-
-static int get_ipipe_mode(struct vpfe_ipipe_device *ipipe)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe);
- u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
-
- if (ipipeif_sink == IPIPEIF_INPUT_MEMORY)
- return IPIPE_MODE_SINGLE_SHOT;
- if (ipipeif_sink == IPIPEIF_INPUT_ISIF)
- return IPIPE_MODE_CONTINUOUS;
-
- return -EINVAL;
-}
-
-int config_ipipe_hw(struct vpfe_ipipe_device *ipipe)
-{
- struct vpfe_ipipe_input_config *config = &ipipe->config.input_config;
- void __iomem *ipipe_base = ipipe->base_addr;
- struct v4l2_mbus_framefmt *outformat;
- u32 color_pat;
- int ipipe_mode;
- u32 data_path;
-
- /* enable clock to IPIPE */
- vpss_enable_clock(VPSS_IPIPE_CLOCK, 1);
- ipipe_clock_enable(ipipe_base);
-
- if (ipipe->input == IPIPE_INPUT_NONE) {
- regw_ip(ipipe_base, 0, IPIPE_SRC_EN);
- return 0;
- }
-
- ipipe_mode = get_ipipe_mode(ipipe);
- if (ipipe_mode < 0) {
- pr_err("Failed to get ipipe mode");
- return -EINVAL;
- }
- regw_ip(ipipe_base, ipipe_mode, IPIPE_SRC_MODE);
-
- data_path = ipipe_get_data_path(ipipe);
- regw_ip(ipipe_base, data_path, IPIPE_SRC_FMT);
-
- regw_ip(ipipe_base, config->vst & IPIPE_RSZ_VPS_MASK, IPIPE_SRC_VPS);
- regw_ip(ipipe_base, config->hst & IPIPE_RSZ_HPS_MASK, IPIPE_SRC_HPS);
-
- outformat = &ipipe->formats[IPIPE_PAD_SOURCE];
- regw_ip(ipipe_base, (outformat->height + 1) & IPIPE_RSZ_VSZ_MASK,
- IPIPE_SRC_VSZ);
- regw_ip(ipipe_base, (outformat->width + 1) & IPIPE_RSZ_HSZ_MASK,
- IPIPE_SRC_HSZ);
-
- if (data_path == IPIPE_RAW2YUV ||
- data_path == IPIPE_RAW2RAW) {
- color_pat =
- ipipe_get_color_pat(ipipe->formats[IPIPE_PAD_SINK].code);
- regw_ip(ipipe_base, color_pat, IPIPE_SRC_COL);
- }
-
- return 0;
-}
-
-/*
- * config_rsz_hw() - Performs hardware setup of resizer.
- */
-int config_rsz_hw(struct vpfe_resizer_device *resizer,
- struct resizer_params *config)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- void __iomem *ipipe_base = vpfe_dev->vpfe_ipipe.base_addr;
- void __iomem *rsz_base = vpfe_dev->vpfe_resizer.base_addr;
-
- /* enable VPSS clock */
- vpss_enable_clock(VPSS_IPIPE_CLOCK, 1);
- ipipe_clock_enable(ipipe_base);
-
- ipipe_setup_resizer(rsz_base, config);
-
- return 0;
-}
-
-static void
-rsz_set_y_address(void __iomem *rsz_base, unsigned int address,
- unsigned int offset)
-{
- u32 val;
-
- val = address & SET_LOW_ADDR;
- regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_BAD_L);
- regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_SAD_L);
-
- val = (address & SET_HIGH_ADDR) >> 16;
- regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_BAD_H);
- regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_SAD_H);
-}
-
-static void
-rsz_set_c_address(void __iomem *rsz_base, unsigned int address,
- unsigned int offset)
-{
- u32 val;
-
- val = address & SET_LOW_ADDR;
- regw_rsz(rsz_base, val, offset + RSZ_SDR_C_BAD_L);
- regw_rsz(rsz_base, val, offset + RSZ_SDR_C_SAD_L);
-
- val = (address & SET_HIGH_ADDR) >> 16;
- regw_rsz(rsz_base, val, offset + RSZ_SDR_C_BAD_H);
- regw_rsz(rsz_base, val, offset + RSZ_SDR_C_SAD_H);
-}
-
-/*
- * resizer_set_outaddr() - set the address for given resize_no
- * @rsz_base: resizer base address
- * @params: pointer to ipipe_params structure
- * @resize_no: 0 - Resizer-A, 1 - Resizer B
- * @address: the address to set
- */
-int
-resizer_set_outaddr(void __iomem *rsz_base, struct resizer_params *params,
- int resize_no, unsigned int address)
-{
- struct resizer_scale_param *rsc_param;
- struct rsz_ext_mem_param *mem_param;
- struct rsz_common_params *rsz_common;
- unsigned int rsz_start_add;
- unsigned int val;
-
- if (resize_no != RSZ_A && resize_no != RSZ_B)
- return -EINVAL;
-
- mem_param = &params->ext_mem_param[resize_no];
- rsc_param = &params->rsz_rsc_param[resize_no];
- rsz_common = &params->rsz_common;
-
- if (resize_no == RSZ_A)
- rsz_start_add = RSZ_EN_A;
- else
- rsz_start_add = RSZ_EN_B;
-
- /* y_c = 0 for y, = 1 for c */
- if (rsz_common->src_img_fmt == RSZ_IMG_420) {
- if (rsz_common->y_c) {
- /* C channel */
- val = address + mem_param->flip_ofst_c;
- rsz_set_c_address(rsz_base, val, rsz_start_add);
- } else {
- val = address + mem_param->flip_ofst_y;
- rsz_set_y_address(rsz_base, val, rsz_start_add);
- }
- } else {
- if (rsc_param->cen && rsc_param->yen) {
- /* 420 */
- val = address + mem_param->c_offset +
- mem_param->flip_ofst_c +
- mem_param->user_y_ofst +
- mem_param->user_c_ofst;
- if (resize_no == RSZ_B)
- val +=
- params->ext_mem_param[RSZ_A].user_y_ofst +
- params->ext_mem_param[RSZ_A].user_c_ofst;
- /* set C address */
- rsz_set_c_address(rsz_base, val, rsz_start_add);
- }
- val = address + mem_param->flip_ofst_y + mem_param->user_y_ofst;
- if (resize_no == RSZ_B)
- val += params->ext_mem_param[RSZ_A].user_y_ofst +
- params->ext_mem_param[RSZ_A].user_c_ofst;
- /* set Y address */
- rsz_set_y_address(rsz_base, val, rsz_start_add);
- }
- /* resizer must be enabled */
- regw_rsz(rsz_base, params->rsz_en[resize_no], rsz_start_add);
-
- return 0;
-}
-
-void
-ipipe_set_lutdpc_regs(void __iomem *base_addr, void __iomem *isp5_base_addr,
- struct vpfe_ipipe_lutdpc *dpc)
-{
- u32 max_tbl_size = LUT_DPC_MAX_SIZE >> 1;
- u32 lut_start_addr = DPC_TB0_START_ADDR;
- u32 val;
- u32 count;
-
- ipipe_clock_enable(base_addr);
- regw_ip(base_addr, dpc->en, DPC_LUT_EN);
-
- if (dpc->en != 1)
- return;
-
- val = LUTDPC_TBL_256_EN | (dpc->repl_white & 1);
- regw_ip(base_addr, val, DPC_LUT_SEL);
- regw_ip(base_addr, LUT_DPC_START_ADDR, DPC_LUT_ADR);
- regw_ip(base_addr, dpc->dpc_size, DPC_LUT_SIZ & LUT_DPC_SIZE_MASK);
-
- for (count = 0; count < dpc->dpc_size; count++) {
- if (count >= max_tbl_size)
- lut_start_addr = DPC_TB1_START_ADDR;
- val = (dpc->table[count].horz_pos & LUT_DPC_H_POS_MASK) |
- ((dpc->table[count].vert_pos & LUT_DPC_V_POS_MASK) <<
- LUT_DPC_V_POS_SHIFT) | (dpc->table[count].method <<
- LUT_DPC_CORR_METH_SHIFT);
- w_ip_table(isp5_base_addr, val, (lut_start_addr +
- ((count % max_tbl_size) << 2)));
- }
-}
-
-static void
-set_dpc_thresholds(void __iomem *base_addr,
- struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_thr)
-{
- regw_ip(base_addr, dpc_thr->corr_thr.r & OTFDPC_DPC2_THR_MASK,
- DPC_OTF_2C_THR_R);
- regw_ip(base_addr, dpc_thr->corr_thr.gr & OTFDPC_DPC2_THR_MASK,
- DPC_OTF_2C_THR_GR);
- regw_ip(base_addr, dpc_thr->corr_thr.gb & OTFDPC_DPC2_THR_MASK,
- DPC_OTF_2C_THR_GB);
- regw_ip(base_addr, dpc_thr->corr_thr.b & OTFDPC_DPC2_THR_MASK,
- DPC_OTF_2C_THR_B);
- regw_ip(base_addr, dpc_thr->det_thr.r & OTFDPC_DPC2_THR_MASK,
- DPC_OTF_2D_THR_R);
- regw_ip(base_addr, dpc_thr->det_thr.gr & OTFDPC_DPC2_THR_MASK,
- DPC_OTF_2D_THR_GR);
- regw_ip(base_addr, dpc_thr->det_thr.gb & OTFDPC_DPC2_THR_MASK,
- DPC_OTF_2D_THR_GB);
- regw_ip(base_addr, dpc_thr->det_thr.b & OTFDPC_DPC2_THR_MASK,
- DPC_OTF_2D_THR_B);
-}
-
-void ipipe_set_otfdpc_regs(void __iomem *base_addr,
- struct vpfe_ipipe_otfdpc *otfdpc)
-{
- struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_2_0 = &otfdpc->alg_cfg.dpc_2_0;
- struct vpfe_ipipe_otfdpc_3_0_cfg *dpc_3_0 = &otfdpc->alg_cfg.dpc_3_0;
- u32 val;
-
- ipipe_clock_enable(base_addr);
-
- regw_ip(base_addr, (otfdpc->en & 1), DPC_OTF_EN);
- if (!otfdpc->en)
- return;
-
- /* dpc enabled */
- val = (otfdpc->det_method << OTF_DET_METHOD_SHIFT) | otfdpc->alg;
- regw_ip(base_addr, val, DPC_OTF_TYP);
-
- if (otfdpc->det_method == VPFE_IPIPE_DPC_OTF_MIN_MAX) {
- /* ALG= 0, TYP = 0, DPC_OTF_2D_THR_[x]=0
- * DPC_OTF_2C_THR_[x] = Maximum thresohld
- * MinMax method
- */
- dpc_2_0->det_thr.r = dpc_2_0->det_thr.gb =
- dpc_2_0->det_thr.gr = dpc_2_0->det_thr.b = 0;
- set_dpc_thresholds(base_addr, dpc_2_0);
- return;
- }
- /* MinMax2 */
- if (otfdpc->alg == VPFE_IPIPE_OTFDPC_2_0) {
- set_dpc_thresholds(base_addr, dpc_2_0);
- return;
- }
- regw_ip(base_addr, dpc_3_0->act_adj_shf &
- OTF_DPC3_0_SHF_MASK, DPC_OTF_3_SHF);
- /* Detection thresholds */
- regw_ip(base_addr, ((dpc_3_0->det_thr & OTF_DPC3_0_THR_MASK) <<
- OTF_DPC3_0_THR_SHIFT), DPC_OTF_3D_THR);
- regw_ip(base_addr, dpc_3_0->det_slp &
- OTF_DPC3_0_SLP_MASK, DPC_OTF_3D_SLP);
- regw_ip(base_addr, dpc_3_0->det_thr_min &
- OTF_DPC3_0_DET_MASK, DPC_OTF_3D_MIN);
- regw_ip(base_addr, dpc_3_0->det_thr_max &
- OTF_DPC3_0_DET_MASK, DPC_OTF_3D_MAX);
- /* Correction thresholds */
- regw_ip(base_addr, ((dpc_3_0->corr_thr & OTF_DPC3_0_THR_MASK) <<
- OTF_DPC3_0_THR_SHIFT), DPC_OTF_3C_THR);
- regw_ip(base_addr, dpc_3_0->corr_slp &
- OTF_DPC3_0_SLP_MASK, DPC_OTF_3C_SLP);
- regw_ip(base_addr, dpc_3_0->corr_thr_min &
- OTF_DPC3_0_CORR_MASK, DPC_OTF_3C_MIN);
- regw_ip(base_addr, dpc_3_0->corr_thr_max &
- OTF_DPC3_0_CORR_MASK, DPC_OTF_3C_MAX);
-}
-
-/* 2D Noise filter */
-void
-ipipe_set_d2f_regs(void __iomem *base_addr, unsigned int id,
- struct vpfe_ipipe_nf *noise_filter)
-{
-
- u32 offset = D2F_1ST;
- int count;
- u32 val;
-
- if (id == IPIPE_D2F_2ND)
- offset = D2F_2ND;
-
- ipipe_clock_enable(base_addr);
- regw_ip(base_addr, noise_filter->en & 1, offset + D2F_EN);
- if (!noise_filter->en)
- return;
-
- /*noise filter enabled */
- /* Combine all the fields to make D2F_CFG register of IPIPE */
- val = ((noise_filter->spread_val & D2F_SPR_VAL_MASK) <<
- D2F_SPR_VAL_SHIFT) | ((noise_filter->shft_val &
- D2F_SHFT_VAL_MASK) << D2F_SHFT_VAL_SHIFT) |
- (noise_filter->gr_sample_meth << D2F_SAMPLE_METH_SHIFT) |
- ((noise_filter->apply_lsc_gain & 1) <<
- D2F_APPLY_LSC_GAIN_SHIFT) | D2F_USE_SPR_REG_VAL;
- regw_ip(base_addr, val, offset + D2F_TYP);
-
- /* edge detection minimum */
- regw_ip(base_addr, noise_filter->edge_det_min_thr &
- D2F_EDGE_DET_THR_MASK, offset + D2F_EDG_MIN);
-
- /* edge detection maximum */
- regw_ip(base_addr, noise_filter->edge_det_max_thr &
- D2F_EDGE_DET_THR_MASK, offset + D2F_EDG_MAX);
-
- for (count = 0; count < VPFE_IPIPE_NF_STR_TABLE_SIZE; count++)
- regw_ip(base_addr,
- (noise_filter->str[count] & D2F_STR_VAL_MASK),
- offset + D2F_STR + count * 4);
-
- for (count = 0; count < VPFE_IPIPE_NF_THR_TABLE_SIZE; count++)
- regw_ip(base_addr, noise_filter->thr[count] & D2F_THR_VAL_MASK,
- offset + D2F_THR + count * 4);
-}
-
-#define IPIPE_U8Q5(decimal, integer) \
- (((decimal & 0x1f) | ((integer & 0x7) << 5)))
-
-/* Green Imbalance Correction */
-void ipipe_set_gic_regs(void __iomem *base_addr, struct vpfe_ipipe_gic *gic)
-{
- u32 val;
-
- ipipe_clock_enable(base_addr);
- regw_ip(base_addr, gic->en & 1, GIC_EN);
-
- if (!gic->en)
- return;
-
- /*gic enabled */
- val = (gic->wt_fn_type << GIC_TYP_SHIFT) |
- (gic->thr_sel << GIC_THR_SEL_SHIFT) |
- ((gic->apply_lsc_gain & 1) << GIC_APPLY_LSC_GAIN_SHIFT);
- regw_ip(base_addr, val, GIC_TYP);
-
- regw_ip(base_addr, gic->gain & GIC_GAIN_MASK, GIC_GAN);
-
- if (gic->gic_alg != VPFE_IPIPE_GIC_ALG_ADAPT_GAIN) {
- /* Constant Gain. Set threshold to maximum */
- regw_ip(base_addr, GIC_THR_MASK, GIC_THR);
- return;
- }
-
- if (gic->thr_sel == VPFE_IPIPE_GIC_THR_REG) {
- regw_ip(base_addr, gic->thr & GIC_THR_MASK, GIC_THR);
- regw_ip(base_addr, gic->slope & GIC_SLOPE_MASK, GIC_SLP);
- } else {
- /* Use NF thresholds */
- val = IPIPE_U8Q5(gic->nf2_thr_gain.decimal,
- gic->nf2_thr_gain.integer);
- regw_ip(base_addr, val, GIC_NFGAN);
- }
-}
-
-#define IPIPE_U13Q9(decimal, integer) \
- (((decimal & 0x1ff) | ((integer & 0xf) << 9)))
-/* White balance */
-void ipipe_set_wb_regs(void __iomem *base_addr, struct vpfe_ipipe_wb *wb)
-{
- u32 val;
-
- ipipe_clock_enable(base_addr);
- /* Ofsets. S12 */
- regw_ip(base_addr, wb->ofst_r & WB_OFFSET_MASK, WB2_OFT_R);
- regw_ip(base_addr, wb->ofst_gr & WB_OFFSET_MASK, WB2_OFT_GR);
- regw_ip(base_addr, wb->ofst_gb & WB_OFFSET_MASK, WB2_OFT_GB);
- regw_ip(base_addr, wb->ofst_b & WB_OFFSET_MASK, WB2_OFT_B);
-
- /* Gains. U13Q9 */
- val = IPIPE_U13Q9(wb->gain_r.decimal, wb->gain_r.integer);
- regw_ip(base_addr, val, WB2_WGN_R);
-
- val = IPIPE_U13Q9(wb->gain_gr.decimal, wb->gain_gr.integer);
- regw_ip(base_addr, val, WB2_WGN_GR);
-
- val = IPIPE_U13Q9(wb->gain_gb.decimal, wb->gain_gb.integer);
- regw_ip(base_addr, val, WB2_WGN_GB);
-
- val = IPIPE_U13Q9(wb->gain_b.decimal, wb->gain_b.integer);
- regw_ip(base_addr, val, WB2_WGN_B);
-}
-
-/* CFA */
-void ipipe_set_cfa_regs(void __iomem *base_addr, struct vpfe_ipipe_cfa *cfa)
-{
- ipipe_clock_enable(base_addr);
-
- regw_ip(base_addr, cfa->alg, CFA_MODE);
- regw_ip(base_addr, cfa->hpf_thr_2dir & CFA_HPF_THR_2DIR_MASK,
- CFA_2DIR_HPF_THR);
- regw_ip(base_addr, cfa->hpf_slp_2dir & CFA_HPF_SLOPE_2DIR_MASK,
- CFA_2DIR_HPF_SLP);
- regw_ip(base_addr, cfa->hp_mix_thr_2dir & CFA_HPF_MIX_THR_2DIR_MASK,
- CFA_2DIR_MIX_THR);
- regw_ip(base_addr, cfa->hp_mix_slope_2dir & CFA_HPF_MIX_SLP_2DIR_MASK,
- CFA_2DIR_MIX_SLP);
- regw_ip(base_addr, cfa->dir_thr_2dir & CFA_DIR_THR_2DIR_MASK,
- CFA_2DIR_DIR_THR);
- regw_ip(base_addr, cfa->dir_slope_2dir & CFA_DIR_SLP_2DIR_MASK,
- CFA_2DIR_DIR_SLP);
- regw_ip(base_addr, cfa->nd_wt_2dir & CFA_ND_WT_2DIR_MASK,
- CFA_2DIR_NDWT);
- regw_ip(base_addr, cfa->hue_fract_daa & CFA_DAA_HUE_FRA_MASK,
- CFA_MONO_HUE_FRA);
- regw_ip(base_addr, cfa->edge_thr_daa & CFA_DAA_EDG_THR_MASK,
- CFA_MONO_EDG_THR);
- regw_ip(base_addr, cfa->thr_min_daa & CFA_DAA_THR_MIN_MASK,
- CFA_MONO_THR_MIN);
- regw_ip(base_addr, cfa->thr_slope_daa & CFA_DAA_THR_SLP_MASK,
- CFA_MONO_THR_SLP);
- regw_ip(base_addr, cfa->slope_min_daa & CFA_DAA_SLP_MIN_MASK,
- CFA_MONO_SLP_MIN);
- regw_ip(base_addr, cfa->slope_slope_daa & CFA_DAA_SLP_SLP_MASK,
- CFA_MONO_SLP_SLP);
- regw_ip(base_addr, cfa->lp_wt_daa & CFA_DAA_LP_WT_MASK,
- CFA_MONO_LPWT);
-}
-
-void
-ipipe_set_rgb2rgb_regs(void __iomem *base_addr, unsigned int id,
- struct vpfe_ipipe_rgb2rgb *rgb)
-{
- u32 offset_mask = RGB2RGB_1_OFST_MASK;
- u32 offset = RGB1_MUL_BASE;
- u32 integ_mask = 0xf;
- u32 val;
-
- ipipe_clock_enable(base_addr);
-
- if (id == IPIPE_RGB2RGB_2) {
- /*
- * For second RGB module, gain integer is 3 bits instead
- * of 4, offset has 11 bits insread of 13
- */
- offset = RGB2_MUL_BASE;
- integ_mask = 0x7;
- offset_mask = RGB2RGB_2_OFST_MASK;
- }
- /* Gains */
- val = (rgb->coef_rr.decimal & 0xff) |
- ((rgb->coef_rr.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_RR);
- val = (rgb->coef_gr.decimal & 0xff) |
- ((rgb->coef_gr.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_GR);
- val = (rgb->coef_br.decimal & 0xff) |
- ((rgb->coef_br.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_BR);
- val = (rgb->coef_rg.decimal & 0xff) |
- ((rgb->coef_rg.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_RG);
- val = (rgb->coef_gg.decimal & 0xff) |
- ((rgb->coef_gg.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_GG);
- val = (rgb->coef_bg.decimal & 0xff) |
- ((rgb->coef_bg.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_BG);
- val = (rgb->coef_rb.decimal & 0xff) |
- ((rgb->coef_rb.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_RB);
- val = (rgb->coef_gb.decimal & 0xff) |
- ((rgb->coef_gb.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_GB);
- val = (rgb->coef_bb.decimal & 0xff) |
- ((rgb->coef_bb.integer & integ_mask) << 8);
- regw_ip(base_addr, val, offset + RGB_MUL_BB);
-
- /* Offsets */
- regw_ip(base_addr, rgb->out_ofst_r & offset_mask, offset + RGB_OFT_OR);
- regw_ip(base_addr, rgb->out_ofst_g & offset_mask, offset + RGB_OFT_OG);
- regw_ip(base_addr, rgb->out_ofst_b & offset_mask, offset + RGB_OFT_OB);
-}
-
-static void
-ipipe_update_gamma_tbl(void __iomem *isp5_base_addr,
- struct vpfe_ipipe_gamma_entry *table, int size, u32 addr)
-{
- int count;
- u32 val;
-
- for (count = 0; count < size; count++) {
- val = table[count].slope & GAMMA_MASK;
- val |= (table[count].offset & GAMMA_MASK) << GAMMA_SHIFT;
- w_ip_table(isp5_base_addr, val, (addr + (count * 4)));
- }
-}
-
-void
-ipipe_set_gamma_regs(void __iomem *base_addr, void __iomem *isp5_base_addr,
- struct vpfe_ipipe_gamma *gamma)
-{
- int table_size;
- u32 val;
-
- ipipe_clock_enable(base_addr);
- val = (gamma->bypass_r << GAMMA_BYPR_SHIFT) |
- (gamma->bypass_b << GAMMA_BYPG_SHIFT) |
- (gamma->bypass_g << GAMMA_BYPB_SHIFT) |
- (gamma->tbl_sel << GAMMA_TBL_SEL_SHIFT) |
- (gamma->tbl_size << GAMMA_TBL_SIZE_SHIFT);
-
- regw_ip(base_addr, val, GMM_CFG);
-
- if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM)
- return;
-
- table_size = gamma->tbl_size;
-
- if (!gamma->bypass_r)
- ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_r,
- table_size, GAMMA_R_START_ADDR);
- if (!gamma->bypass_b)
- ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_b,
- table_size, GAMMA_B_START_ADDR);
- if (!gamma->bypass_g)
- ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_g,
- table_size, GAMMA_G_START_ADDR);
-}
-
-void
-ipipe_set_3d_lut_regs(void __iomem *base_addr, void __iomem *isp5_base_addr,
- struct vpfe_ipipe_3d_lut *lut_3d)
-{
- struct vpfe_ipipe_3d_lut_entry *tbl;
- u32 bnk_index;
- u32 tbl_index;
- u32 val;
- u32 i;
-
- ipipe_clock_enable(base_addr);
- regw_ip(base_addr, lut_3d->en, D3LUT_EN);
-
- if (!lut_3d->en)
- return;
-
- /* valid table */
- tbl = lut_3d->table;
- for (i = 0; i < VPFE_IPIPE_MAX_SIZE_3D_LUT; i++) {
- /*
- * Each entry has 0-9 (B), 10-19 (G) and
- * 20-29 R values
- */
- val = tbl[i].b & D3_LUT_ENTRY_MASK;
- val |= (tbl[i].g & D3_LUT_ENTRY_MASK) <<
- D3_LUT_ENTRY_G_SHIFT;
- val |= (tbl[i].r & D3_LUT_ENTRY_MASK) <<
- D3_LUT_ENTRY_R_SHIFT;
- bnk_index = i % 4;
- tbl_index = i >> 2;
- tbl_index <<= 2;
- if (bnk_index == 0)
- w_ip_table(isp5_base_addr, val,
- tbl_index + D3L_TB0_START_ADDR);
- else if (bnk_index == 1)
- w_ip_table(isp5_base_addr, val,
- tbl_index + D3L_TB1_START_ADDR);
- else if (bnk_index == 2)
- w_ip_table(isp5_base_addr, val,
- tbl_index + D3L_TB2_START_ADDR);
- else
- w_ip_table(isp5_base_addr, val,
- tbl_index + D3L_TB3_START_ADDR);
- }
-}
-
-/* Lumina adjustments */
-void
-ipipe_set_lum_adj_regs(void __iomem *base_addr, struct ipipe_lum_adj *lum_adj)
-{
- u32 val;
-
- ipipe_clock_enable(base_addr);
-
- /* combine fields of YUV_ADJ to set brightness and contrast */
- val = lum_adj->contrast << LUM_ADJ_CONTR_SHIFT |
- lum_adj->brightness << LUM_ADJ_BRIGHT_SHIFT;
- regw_ip(base_addr, val, YUV_ADJ);
-}
-
-inline u32 ipipe_s12q8(unsigned short decimal, short integer)
-{
- return (decimal & 0xff) | ((integer & 0xf) << 8);
-}
-
-void ipipe_set_rgb2ycbcr_regs(void __iomem *base_addr,
- struct vpfe_ipipe_rgb2yuv *yuv)
-{
- u32 val;
-
- /* S10Q8 */
- ipipe_clock_enable(base_addr);
- val = ipipe_s12q8(yuv->coef_ry.decimal, yuv->coef_ry.integer);
- regw_ip(base_addr, val, YUV_MUL_RY);
- val = ipipe_s12q8(yuv->coef_gy.decimal, yuv->coef_gy.integer);
- regw_ip(base_addr, val, YUV_MUL_GY);
- val = ipipe_s12q8(yuv->coef_by.decimal, yuv->coef_by.integer);
- regw_ip(base_addr, val, YUV_MUL_BY);
- val = ipipe_s12q8(yuv->coef_rcb.decimal, yuv->coef_rcb.integer);
- regw_ip(base_addr, val, YUV_MUL_RCB);
- val = ipipe_s12q8(yuv->coef_gcb.decimal, yuv->coef_gcb.integer);
- regw_ip(base_addr, val, YUV_MUL_GCB);
- val = ipipe_s12q8(yuv->coef_bcb.decimal, yuv->coef_bcb.integer);
- regw_ip(base_addr, val, YUV_MUL_BCB);
- val = ipipe_s12q8(yuv->coef_rcr.decimal, yuv->coef_rcr.integer);
- regw_ip(base_addr, val, YUV_MUL_RCR);
- val = ipipe_s12q8(yuv->coef_gcr.decimal, yuv->coef_gcr.integer);
- regw_ip(base_addr, val, YUV_MUL_GCR);
- val = ipipe_s12q8(yuv->coef_bcr.decimal, yuv->coef_bcr.integer);
- regw_ip(base_addr, val, YUV_MUL_BCR);
- regw_ip(base_addr, yuv->out_ofst_y & RGB2YCBCR_OFST_MASK, YUV_OFT_Y);
- regw_ip(base_addr, yuv->out_ofst_cb & RGB2YCBCR_OFST_MASK, YUV_OFT_CB);
- regw_ip(base_addr, yuv->out_ofst_cr & RGB2YCBCR_OFST_MASK, YUV_OFT_CR);
-}
-
-/* YUV 422 conversion */
-void
-ipipe_set_yuv422_conv_regs(void __iomem *base_addr,
- struct vpfe_ipipe_yuv422_conv *conv)
-{
- u32 val;
-
- ipipe_clock_enable(base_addr);
-
- /* Combine all the fields to make YUV_PHS register of IPIPE */
- val = (conv->chrom_pos << 0) | (conv->en_chrom_lpf << 1);
- regw_ip(base_addr, val, YUV_PHS);
-}
-
-void
-ipipe_set_gbce_regs(void __iomem *base_addr, void __iomem *isp5_base_addr,
- struct vpfe_ipipe_gbce *gbce)
-{
- unsigned int count;
- u32 mask = GBCE_Y_VAL_MASK;
-
- if (gbce->type == VPFE_IPIPE_GBCE_GAIN_TBL)
- mask = GBCE_GAIN_VAL_MASK;
-
- ipipe_clock_enable(base_addr);
- regw_ip(base_addr, gbce->en & 1, GBCE_EN);
-
- if (!gbce->en)
- return;
-
- regw_ip(base_addr, gbce->type, GBCE_TYP);
-
- for (count = 0; count < VPFE_IPIPE_MAX_SIZE_GBCE_LUT; count += 2)
- w_ip_table(isp5_base_addr, ((gbce->table[count + 1] & mask) <<
- GBCE_ENTRY_SHIFT) | (gbce->table[count] & mask),
- ((count/2) << 2) + GBCE_TB_START_ADDR);
-}
-
-void
-ipipe_set_ee_regs(void __iomem *base_addr, void __iomem *isp5_base_addr,
- struct vpfe_ipipe_yee *ee)
-{
- unsigned int count;
- u32 val;
-
- ipipe_clock_enable(base_addr);
- regw_ip(base_addr, ee->en, YEE_EN);
-
- if (!ee->en)
- return;
-
- val = ee->en_halo_red & 1;
- val |= ee->merge_meth << YEE_HALO_RED_EN_SHIFT;
- regw_ip(base_addr, val, YEE_TYP);
-
- regw_ip(base_addr, ee->hpf_shft, YEE_SHF);
- regw_ip(base_addr, ee->hpf_coef_00 & YEE_COEF_MASK, YEE_MUL_00);
- regw_ip(base_addr, ee->hpf_coef_01 & YEE_COEF_MASK, YEE_MUL_01);
- regw_ip(base_addr, ee->hpf_coef_02 & YEE_COEF_MASK, YEE_MUL_02);
- regw_ip(base_addr, ee->hpf_coef_10 & YEE_COEF_MASK, YEE_MUL_10);
- regw_ip(base_addr, ee->hpf_coef_11 & YEE_COEF_MASK, YEE_MUL_11);
- regw_ip(base_addr, ee->hpf_coef_12 & YEE_COEF_MASK, YEE_MUL_12);
- regw_ip(base_addr, ee->hpf_coef_20 & YEE_COEF_MASK, YEE_MUL_20);
- regw_ip(base_addr, ee->hpf_coef_21 & YEE_COEF_MASK, YEE_MUL_21);
- regw_ip(base_addr, ee->hpf_coef_22 & YEE_COEF_MASK, YEE_MUL_22);
- regw_ip(base_addr, ee->yee_thr & YEE_THR_MASK, YEE_THR);
- regw_ip(base_addr, ee->es_gain & YEE_ES_GAIN_MASK, YEE_E_GAN);
- regw_ip(base_addr, ee->es_thr1 & YEE_ES_THR1_MASK, YEE_E_THR1);
- regw_ip(base_addr, ee->es_thr2 & YEE_THR_MASK, YEE_E_THR2);
- regw_ip(base_addr, ee->es_gain_grad & YEE_THR_MASK, YEE_G_GAN);
- regw_ip(base_addr, ee->es_ofst_grad & YEE_THR_MASK, YEE_G_OFT);
-
- for (count = 0; count < VPFE_IPIPE_MAX_SIZE_YEE_LUT; count += 2)
- w_ip_table(isp5_base_addr, ((ee->table[count + 1] &
- YEE_ENTRY_MASK) << YEE_ENTRY_SHIFT) |
- (ee->table[count] & YEE_ENTRY_MASK),
- ((count/2) << 2) + YEE_TB_START_ADDR);
-}
-
-/* Chromatic Artifact Correction. CAR */
-static void ipipe_set_mf(void __iomem *base_addr)
-{
- /* typ to dynamic switch */
- regw_ip(base_addr, VPFE_IPIPE_CAR_DYN_SWITCH, CAR_TYP);
- /* Set SW0 to maximum */
- regw_ip(base_addr, CAR_MF_THR, CAR_SW);
-}
-
-static void
-ipipe_set_gain_ctrl(void __iomem *base_addr, struct vpfe_ipipe_car *car)
-{
- regw_ip(base_addr, VPFE_IPIPE_CAR_CHR_GAIN_CTRL, CAR_TYP);
- regw_ip(base_addr, car->hpf, CAR_HPF_TYP);
- regw_ip(base_addr, car->hpf_shft & CAR_HPF_SHIFT_MASK, CAR_HPF_SHF);
- regw_ip(base_addr, car->hpf_thr, CAR_HPF_THR);
- regw_ip(base_addr, car->gain1.gain, CAR_GN1_GAN);
- regw_ip(base_addr, car->gain1.shft & CAR_GAIN1_SHFT_MASK, CAR_GN1_SHF);
- regw_ip(base_addr, car->gain1.gain_min & CAR_GAIN_MIN_MASK,
- CAR_GN1_MIN);
- regw_ip(base_addr, car->gain2.gain, CAR_GN2_GAN);
- regw_ip(base_addr, car->gain2.shft & CAR_GAIN2_SHFT_MASK, CAR_GN2_SHF);
- regw_ip(base_addr, car->gain2.gain_min & CAR_GAIN_MIN_MASK,
- CAR_GN2_MIN);
-}
-
-void ipipe_set_car_regs(void __iomem *base_addr, struct vpfe_ipipe_car *car)
-{
- u32 val;
-
- ipipe_clock_enable(base_addr);
- regw_ip(base_addr, car->en, CAR_EN);
-
- if (!car->en)
- return;
-
- switch (car->meth) {
- case VPFE_IPIPE_CAR_MED_FLTR:
- ipipe_set_mf(base_addr);
- break;
-
- case VPFE_IPIPE_CAR_CHR_GAIN_CTRL:
- ipipe_set_gain_ctrl(base_addr, car);
- break;
-
- default:
- /* Dynamic switch between MF and Gain Ctrl. */
- ipipe_set_mf(base_addr);
- ipipe_set_gain_ctrl(base_addr, car);
- /* Set the threshold for switching between
- * the two Here we overwrite the MF SW0 value
- */
- regw_ip(base_addr, VPFE_IPIPE_CAR_DYN_SWITCH, CAR_TYP);
- val = car->sw1;
- val <<= CAR_SW1_SHIFT;
- val |= car->sw0;
- regw_ip(base_addr, val, CAR_SW);
- }
-}
-
-/* Chromatic Gain Suppression */
-void ipipe_set_cgs_regs(void __iomem *base_addr, struct vpfe_ipipe_cgs *cgs)
-{
- ipipe_clock_enable(base_addr);
- regw_ip(base_addr, cgs->en, CGS_EN);
-
- if (!cgs->en)
- return;
-
- /* Set the bright side parameters */
- regw_ip(base_addr, cgs->h_thr, CGS_GN1_H_THR);
- regw_ip(base_addr, cgs->h_slope, CGS_GN1_H_GAN);
- regw_ip(base_addr, cgs->h_shft & CAR_SHIFT_MASK, CGS_GN1_H_SHF);
- regw_ip(base_addr, cgs->h_min, CGS_GN1_H_MIN);
-}
-
-void rsz_src_enable(void __iomem *rsz_base, int enable)
-{
- regw_rsz(rsz_base, enable, RSZ_SRC_EN);
-}
-
-int rsz_enable(void __iomem *rsz_base, int rsz_id, int enable)
-{
- if (rsz_id == RSZ_A) {
- regw_rsz(rsz_base, enable, RSZ_EN_A);
- /* We always enable RSZ_A. RSZ_B is enable upon request from
- * application. So enable RSZ_SRC_EN along with RSZ_A
- */
- regw_rsz(rsz_base, enable, RSZ_SRC_EN);
- } else if (rsz_id == RSZ_B) {
- regw_rsz(rsz_base, enable, RSZ_EN_B);
- } else {
- BUG();
- }
-
- return 0;
-}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h
deleted file mode 100644
index 16b6a14b7058..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h
+++ /dev/null
@@ -1,556 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_DM365_IPIPE_HW_H
-#define _DAVINCI_VPFE_DM365_IPIPE_HW_H
-
-#include "vpfe_mc_capture.h"
-
-#define SET_LOW_ADDR 0x0000ffff
-#define SET_HIGH_ADDR 0xffff0000
-
-/* Below are the internal tables */
-#define DPC_TB0_START_ADDR 0x8000
-#define DPC_TB1_START_ADDR 0x8400
-
-#define GAMMA_R_START_ADDR 0xa800
-#define GAMMA_G_START_ADDR 0xb000
-#define GAMMA_B_START_ADDR 0xb800
-
-/* RAM table addresses for edge enhancement correction*/
-#define YEE_TB_START_ADDR 0x8800
-
-/* RAM table address for GBC LUT */
-#define GBCE_TB_START_ADDR 0x9000
-
-/* RAM table for 3D NF LUT */
-#define D3L_TB0_START_ADDR 0x9800
-#define D3L_TB1_START_ADDR 0x9c00
-#define D3L_TB2_START_ADDR 0xa000
-#define D3L_TB3_START_ADDR 0xa400
-
-/* IPIPE Register Offsets from the base address */
-#define IPIPE_SRC_EN 0x0000
-#define IPIPE_SRC_MODE 0x0004
-#define IPIPE_SRC_FMT 0x0008
-#define IPIPE_SRC_COL 0x000c
-#define IPIPE_SRC_VPS 0x0010
-#define IPIPE_SRC_VSZ 0x0014
-#define IPIPE_SRC_HPS 0x0018
-#define IPIPE_SRC_HSZ 0x001c
-
-#define IPIPE_SEL_SBU 0x0020
-
-#define IPIPE_DMA_STA 0x0024
-#define IPIPE_GCK_MMR 0x0028
-#define IPIPE_GCK_PIX 0x002c
-#define IPIPE_RESERVED0 0x0030
-
-/* Defect Correction */
-#define DPC_LUT_EN 0x0034
-#define DPC_LUT_SEL 0x0038
-#define DPC_LUT_ADR 0x003c
-#define DPC_LUT_SIZ 0x0040
-#define DPC_OTF_EN 0x0044
-#define DPC_OTF_TYP 0x0048
-#define DPC_OTF_2D_THR_R 0x004c
-#define DPC_OTF_2D_THR_GR 0x0050
-#define DPC_OTF_2D_THR_GB 0x0054
-#define DPC_OTF_2D_THR_B 0x0058
-#define DPC_OTF_2C_THR_R 0x005c
-#define DPC_OTF_2C_THR_GR 0x0060
-#define DPC_OTF_2C_THR_GB 0x0064
-#define DPC_OTF_2C_THR_B 0x0068
-#define DPC_OTF_3_SHF 0x006c
-#define DPC_OTF_3D_THR 0x0070
-#define DPC_OTF_3D_SLP 0x0074
-#define DPC_OTF_3D_MIN 0x0078
-#define DPC_OTF_3D_MAX 0x007c
-#define DPC_OTF_3C_THR 0x0080
-#define DPC_OTF_3C_SLP 0x0084
-#define DPC_OTF_3C_MIN 0x0088
-#define DPC_OTF_3C_MAX 0x008c
-
-/* Lense Shading Correction */
-#define LSC_VOFT 0x90
-#define LSC_VA2 0x94
-#define LSC_VA1 0x98
-#define LSC_VS 0x9c
-#define LSC_HOFT 0xa0
-#define LSC_HA2 0xa4
-#define LSC_HA1 0xa8
-#define LSC_HS 0xac
-#define LSC_GAIN_R 0xb0
-#define LSC_GAIN_GR 0xb4
-#define LSC_GAIN_GB 0xb8
-#define LSC_GAIN_B 0xbc
-#define LSC_OFT_R 0xc0
-#define LSC_OFT_GR 0xc4
-#define LSC_OFT_GB 0xc8
-#define LSC_OFT_B 0xcc
-#define LSC_SHF 0xd0
-#define LSC_MAX 0xd4
-
-/* Noise Filter 1. Ofsets from start address given */
-#define D2F_1ST 0xd8
-#define D2F_EN 0x0
-#define D2F_TYP 0x4
-#define D2F_THR 0x8
-#define D2F_STR 0x28
-#define D2F_SPR 0x48
-#define D2F_EDG_MIN 0x68
-#define D2F_EDG_MAX 0x6c
-
-/* Noise Filter 2 */
-#define D2F_2ND 0x148
-
-/* GIC */
-#define GIC_EN 0x1b8
-#define GIC_TYP 0x1bc
-#define GIC_GAN 0x1c0
-#define GIC_NFGAN 0x1c4
-#define GIC_THR 0x1c8
-#define GIC_SLP 0x1cc
-
-/* White Balance */
-#define WB2_OFT_R 0x1d0
-#define WB2_OFT_GR 0x1d4
-#define WB2_OFT_GB 0x1d8
-#define WB2_OFT_B 0x1dc
-#define WB2_WGN_R 0x1e0
-#define WB2_WGN_GR 0x1e4
-#define WB2_WGN_GB 0x1e8
-#define WB2_WGN_B 0x1ec
-
-/* CFA interpolation */
-#define CFA_MODE 0x1f0
-#define CFA_2DIR_HPF_THR 0x1f4
-#define CFA_2DIR_HPF_SLP 0x1f8
-#define CFA_2DIR_MIX_THR 0x1fc
-#define CFA_2DIR_MIX_SLP 0x200
-#define CFA_2DIR_DIR_THR 0x204
-#define CFA_2DIR_DIR_SLP 0x208
-#define CFA_2DIR_NDWT 0x20c
-#define CFA_MONO_HUE_FRA 0x210
-#define CFA_MONO_EDG_THR 0x214
-#define CFA_MONO_THR_MIN 0x218
-#define CFA_MONO_THR_SLP 0x21c
-#define CFA_MONO_SLP_MIN 0x220
-#define CFA_MONO_SLP_SLP 0x224
-#define CFA_MONO_LPWT 0x228
-
-/* RGB to RGB conversiona - 1st */
-#define RGB1_MUL_BASE 0x22c
-/* Offsets from base */
-#define RGB_MUL_RR 0x0
-#define RGB_MUL_GR 0x4
-#define RGB_MUL_BR 0x8
-#define RGB_MUL_RG 0xc
-#define RGB_MUL_GG 0x10
-#define RGB_MUL_BG 0x14
-#define RGB_MUL_RB 0x18
-#define RGB_MUL_GB 0x1c
-#define RGB_MUL_BB 0x20
-#define RGB_OFT_OR 0x24
-#define RGB_OFT_OG 0x28
-#define RGB_OFT_OB 0x2c
-
-/* Gamma */
-#define GMM_CFG 0x25c
-
-/* RGB to RGB conversiona - 2nd */
-#define RGB2_MUL_BASE 0x260
-
-/* 3D LUT */
-#define D3LUT_EN 0x290
-
-/* RGB to YUV(YCbCr) conversion */
-#define YUV_ADJ 0x294
-#define YUV_MUL_RY 0x298
-#define YUV_MUL_GY 0x29c
-#define YUV_MUL_BY 0x2a0
-#define YUV_MUL_RCB 0x2a4
-#define YUV_MUL_GCB 0x2a8
-#define YUV_MUL_BCB 0x2ac
-#define YUV_MUL_RCR 0x2b0
-#define YUV_MUL_GCR 0x2b4
-#define YUV_MUL_BCR 0x2b8
-#define YUV_OFT_Y 0x2bc
-#define YUV_OFT_CB 0x2c0
-#define YUV_OFT_CR 0x2c4
-#define YUV_PHS 0x2c8
-
-/* Global Brightness and Contrast */
-#define GBCE_EN 0x2cc
-#define GBCE_TYP 0x2d0
-
-/* Edge Enhancer */
-#define YEE_EN 0x2d4
-#define YEE_TYP 0x2d8
-#define YEE_SHF 0x2dc
-#define YEE_MUL_00 0x2e0
-#define YEE_MUL_01 0x2e4
-#define YEE_MUL_02 0x2e8
-#define YEE_MUL_10 0x2ec
-#define YEE_MUL_11 0x2f0
-#define YEE_MUL_12 0x2f4
-#define YEE_MUL_20 0x2f8
-#define YEE_MUL_21 0x2fc
-#define YEE_MUL_22 0x300
-#define YEE_THR 0x304
-#define YEE_E_GAN 0x308
-#define YEE_E_THR1 0x30c
-#define YEE_E_THR2 0x310
-#define YEE_G_GAN 0x314
-#define YEE_G_OFT 0x318
-
-/* Chroma Artifact Reduction */
-#define CAR_EN 0x31c
-#define CAR_TYP 0x320
-#define CAR_SW 0x324
-#define CAR_HPF_TYP 0x328
-#define CAR_HPF_SHF 0x32c
-#define CAR_HPF_THR 0x330
-#define CAR_GN1_GAN 0x334
-#define CAR_GN1_SHF 0x338
-#define CAR_GN1_MIN 0x33c
-#define CAR_GN2_GAN 0x340
-#define CAR_GN2_SHF 0x344
-#define CAR_GN2_MIN 0x348
-
-/* Chroma Gain Suppression */
-#define CGS_EN 0x34c
-#define CGS_GN1_L_THR 0x350
-#define CGS_GN1_L_GAN 0x354
-#define CGS_GN1_L_SHF 0x358
-#define CGS_GN1_L_MIN 0x35c
-#define CGS_GN1_H_THR 0x360
-#define CGS_GN1_H_GAN 0x364
-#define CGS_GN1_H_SHF 0x368
-#define CGS_GN1_H_MIN 0x36c
-#define CGS_GN2_L_THR 0x370
-#define CGS_GN2_L_GAN 0x374
-#define CGS_GN2_L_SHF 0x378
-#define CGS_GN2_L_MIN 0x37c
-
-/* Resizer */
-#define RSZ_SRC_EN 0x0
-#define RSZ_SRC_MODE 0x4
-#define RSZ_SRC_FMT0 0x8
-#define RSZ_SRC_FMT1 0xc
-#define RSZ_SRC_VPS 0x10
-#define RSZ_SRC_VSZ 0x14
-#define RSZ_SRC_HPS 0x18
-#define RSZ_SRC_HSZ 0x1c
-#define RSZ_DMA_RZA 0x20
-#define RSZ_DMA_RZB 0x24
-#define RSZ_DMA_STA 0x28
-#define RSZ_GCK_MMR 0x2c
-#define RSZ_RESERVED0 0x30
-#define RSZ_GCK_SDR 0x34
-#define RSZ_IRQ_RZA 0x38
-#define RSZ_IRQ_RZB 0x3c
-#define RSZ_YUV_Y_MIN 0x40
-#define RSZ_YUV_Y_MAX 0x44
-#define RSZ_YUV_C_MIN 0x48
-#define RSZ_YUV_C_MAX 0x4c
-#define RSZ_YUV_PHS 0x50
-#define RSZ_SEQ 0x54
-
-/* Resizer Rescale Parameters */
-#define RSZ_EN_A 0x58
-#define RSZ_EN_B 0xe8
-/*
- * offset of the registers to be added with base register of
- * either RSZ0 or RSZ1
- */
-#define RSZ_MODE 0x4
-#define RSZ_420 0x8
-#define RSZ_I_VPS 0xc
-#define RSZ_I_HPS 0x10
-#define RSZ_O_VSZ 0x14
-#define RSZ_O_HSZ 0x18
-#define RSZ_V_PHS_Y 0x1c
-#define RSZ_V_PHS_C 0x20
-#define RSZ_V_DIF 0x24
-#define RSZ_V_TYP 0x28
-#define RSZ_V_LPF 0x2c
-#define RSZ_H_PHS 0x30
-#define RSZ_H_PHS_ADJ 0x34
-#define RSZ_H_DIF 0x38
-#define RSZ_H_TYP 0x3c
-#define RSZ_H_LPF 0x40
-#define RSZ_DWN_EN 0x44
-#define RSZ_DWN_AV 0x48
-
-/* Resizer RGB Conversion Parameters */
-#define RSZ_RGB_EN 0x4c
-#define RSZ_RGB_TYP 0x50
-#define RSZ_RGB_BLD 0x54
-
-/* Resizer External Memory Parameters */
-#define RSZ_SDR_Y_BAD_H 0x58
-#define RSZ_SDR_Y_BAD_L 0x5c
-#define RSZ_SDR_Y_SAD_H 0x60
-#define RSZ_SDR_Y_SAD_L 0x64
-#define RSZ_SDR_Y_OFT 0x68
-#define RSZ_SDR_Y_PTR_S 0x6c
-#define RSZ_SDR_Y_PTR_E 0x70
-#define RSZ_SDR_C_BAD_H 0x74
-#define RSZ_SDR_C_BAD_L 0x78
-#define RSZ_SDR_C_SAD_H 0x7c
-#define RSZ_SDR_C_SAD_L 0x80
-#define RSZ_SDR_C_OFT 0x84
-#define RSZ_SDR_C_PTR_S 0x88
-#define RSZ_SDR_C_PTR_E 0x8c
-
-/* Macro for resizer */
-#define RSZ_YUV_Y_MIN 0x40
-#define RSZ_YUV_Y_MAX 0x44
-#define RSZ_YUV_C_MIN 0x48
-#define RSZ_YUV_C_MAX 0x4c
-
-#define IPIPE_GCK_MMR_DEFAULT 1
-#define IPIPE_GCK_PIX_DEFAULT 0xe
-#define RSZ_GCK_MMR_DEFAULT 1
-#define RSZ_GCK_SDR_DEFAULT 1
-
-/* LUTDPC */
-#define LUTDPC_TBL_256_EN 0
-#define LUTDPC_INF_TBL_EN 1
-#define LUT_DPC_START_ADDR 0
-#define LUT_DPC_H_POS_MASK 0x1fff
-#define LUT_DPC_V_POS_MASK 0x1fff
-#define LUT_DPC_V_POS_SHIFT 13
-#define LUT_DPC_CORR_METH_SHIFT 26
-#define LUT_DPC_MAX_SIZE 256
-#define LUT_DPC_SIZE_MASK 0x3ff
-
-/* OTFDPC */
-#define OTFDPC_DPC2_THR_MASK 0xfff
-#define OTF_DET_METHOD_SHIFT 1
-#define OTF_DPC3_0_SHF_MASK 3
-#define OTF_DPC3_0_THR_SHIFT 6
-#define OTF_DPC3_0_THR_MASK 0x3f
-#define OTF_DPC3_0_SLP_MASK 0x3f
-#define OTF_DPC3_0_DET_MASK 0xfff
-#define OTF_DPC3_0_CORR_MASK 0xfff
-
-/* NF (D2F) */
-#define D2F_SPR_VAL_MASK 0x1f
-#define D2F_SPR_VAL_SHIFT 0
-#define D2F_SHFT_VAL_MASK 3
-#define D2F_SHFT_VAL_SHIFT 5
-#define D2F_SAMPLE_METH_SHIFT 7
-#define D2F_APPLY_LSC_GAIN_SHIFT 8
-#define D2F_USE_SPR_REG_VAL 0
-#define D2F_STR_VAL_MASK 0x1f
-#define D2F_THR_VAL_MASK 0x3ff
-#define D2F_EDGE_DET_THR_MASK 0x7ff
-
-/* Green Imbalance Correction */
-#define GIC_TYP_SHIFT 0
-#define GIC_THR_SEL_SHIFT 1
-#define GIC_APPLY_LSC_GAIN_SHIFT 2
-#define GIC_GAIN_MASK 0xff
-#define GIC_THR_MASK 0xfff
-#define GIC_SLOPE_MASK 0xfff
-#define GIC_NFGAN_INT_MASK 7
-#define GIC_NFGAN_DECI_MASK 0x1f
-
-/* WB */
-#define WB_OFFSET_MASK 0xfff
-#define WB_GAIN_INT_MASK 0xf
-#define WB_GAIN_DECI_MASK 0x1ff
-
-/* CFA */
-#define CFA_HPF_THR_2DIR_MASK 0x1fff
-#define CFA_HPF_SLOPE_2DIR_MASK 0x3ff
-#define CFA_HPF_MIX_THR_2DIR_MASK 0x1fff
-#define CFA_HPF_MIX_SLP_2DIR_MASK 0x3ff
-#define CFA_DIR_THR_2DIR_MASK 0x3ff
-#define CFA_DIR_SLP_2DIR_MASK 0x7f
-#define CFA_ND_WT_2DIR_MASK 0x3f
-#define CFA_DAA_HUE_FRA_MASK 0x3f
-#define CFA_DAA_EDG_THR_MASK 0xff
-#define CFA_DAA_THR_MIN_MASK 0x3ff
-#define CFA_DAA_THR_SLP_MASK 0x3ff
-#define CFA_DAA_SLP_MIN_MASK 0x3ff
-#define CFA_DAA_SLP_SLP_MASK 0x3ff
-#define CFA_DAA_LP_WT_MASK 0x3f
-
-/* RGB2RGB */
-#define RGB2RGB_1_OFST_MASK 0x1fff
-#define RGB2RGB_1_GAIN_INT_MASK 0xf
-#define RGB2RGB_GAIN_DECI_MASK 0xff
-#define RGB2RGB_2_OFST_MASK 0x7ff
-#define RGB2RGB_2_GAIN_INT_MASK 0x7
-
-/* Gamma */
-#define GAMMA_BYPR_SHIFT 0
-#define GAMMA_BYPG_SHIFT 1
-#define GAMMA_BYPB_SHIFT 2
-#define GAMMA_TBL_SEL_SHIFT 4
-#define GAMMA_TBL_SIZE_SHIFT 5
-#define GAMMA_MASK 0x3ff
-#define GAMMA_SHIFT 10
-
-/* 3D LUT */
-#define D3_LUT_ENTRY_MASK 0x3ff
-#define D3_LUT_ENTRY_R_SHIFT 20
-#define D3_LUT_ENTRY_G_SHIFT 10
-#define D3_LUT_ENTRY_B_SHIFT 0
-
-/* Lumina adj */
-#define LUM_ADJ_CONTR_SHIFT 0
-#define LUM_ADJ_BRIGHT_SHIFT 8
-
-/* RGB2YCbCr */
-#define RGB2YCBCR_OFST_MASK 0x7ff
-#define RGB2YCBCR_COEF_INT_MASK 0xf
-#define RGB2YCBCR_COEF_DECI_MASK 0xff
-
-/* GBCE */
-#define GBCE_Y_VAL_MASK 0xff
-#define GBCE_GAIN_VAL_MASK 0x3ff
-#define GBCE_ENTRY_SHIFT 10
-
-/* Edge Enhancements */
-#define YEE_HALO_RED_EN_SHIFT 1
-#define YEE_HPF_SHIFT_MASK 0xf
-#define YEE_COEF_MASK 0x3ff
-#define YEE_THR_MASK 0x3f
-#define YEE_ES_GAIN_MASK 0xfff
-#define YEE_ES_THR1_MASK 0xfff
-#define YEE_ENTRY_SHIFT 9
-#define YEE_ENTRY_MASK 0x1ff
-
-/* CAR */
-#define CAR_MF_THR 0xff
-#define CAR_SW1_SHIFT 8
-#define CAR_GAIN1_SHFT_MASK 7
-#define CAR_GAIN_MIN_MASK 0x1ff
-#define CAR_GAIN2_SHFT_MASK 0xf
-#define CAR_HPF_SHIFT_MASK 3
-
-/* CGS */
-#define CAR_SHIFT_MASK 3
-
-/* Resizer */
-#define RSZ_BYPASS_SHIFT 1
-#define RSZ_SRC_IMG_FMT_SHIFT 1
-#define RSZ_SRC_Y_C_SEL_SHIFT 2
-#define IPIPE_RSZ_VPS_MASK 0xffff
-#define IPIPE_RSZ_HPS_MASK 0xffff
-#define IPIPE_RSZ_VSZ_MASK 0x1fff
-#define IPIPE_RSZ_HSZ_MASK 0x1fff
-#define RSZ_HPS_MASK 0x1fff
-#define RSZ_VPS_MASK 0x1fff
-#define RSZ_O_HSZ_MASK 0x1fff
-#define RSZ_O_VSZ_MASK 0x1fff
-#define RSZ_V_PHS_MASK 0x3fff
-#define RSZ_V_DIF_MASK 0x3fff
-
-#define RSZA_H_FLIP_SHIFT 0
-#define RSZA_V_FLIP_SHIFT 1
-#define RSZB_H_FLIP_SHIFT 2
-#define RSZB_V_FLIP_SHIFT 3
-#define RSZ_A 0
-#define RSZ_B 1
-#define RSZ_CEN_SHIFT 1
-#define RSZ_YEN_SHIFT 0
-#define RSZ_TYP_Y_SHIFT 0
-#define RSZ_TYP_C_SHIFT 1
-#define RSZ_LPF_INT_MASK 0x3f
-#define RSZ_LPF_INT_C_SHIFT 6
-#define RSZ_H_PHS_MASK 0x3fff
-#define RSZ_H_DIF_MASK 0x3fff
-#define RSZ_DIFF_DOWN_THR 256
-#define RSZ_DWN_SCALE_AV_SZ_V_SHIFT 3
-#define RSZ_DWN_SCALE_AV_SZ_MASK 7
-#define RSZ_RGB_MSK1_SHIFT 2
-#define RSZ_RGB_MSK0_SHIFT 1
-#define RSZ_RGB_TYP_SHIFT 0
-#define RSZ_RGB_ALPHA_MASK 0xff
-
-static inline u32 regr_ip(void __iomem *addr, u32 offset)
-{
- return readl(addr + offset);
-}
-
-static inline void regw_ip(void __iomem *addr, u32 val, u32 offset)
-{
- writel(val, addr + offset);
-}
-
-static inline u32 w_ip_table(void __iomem *addr, u32 val, u32 offset)
-{
- writel(val, addr + offset);
-
- return val;
-}
-
-static inline u32 regr_rsz(void __iomem *addr, u32 offset)
-{
- return readl(addr + offset);
-}
-
-static inline u32 regw_rsz(void __iomem *addr, u32 val, u32 offset)
-{
- writel(val, addr + offset);
-
- return val;
-}
-
-int config_ipipe_hw(struct vpfe_ipipe_device *ipipe);
-int resizer_set_outaddr(void __iomem *rsz_base, struct resizer_params *params,
- int resize_no, unsigned int address);
-int rsz_enable(void __iomem *rsz_base, int rsz_id, int enable);
-void rsz_src_enable(void __iomem *rsz_base, int enable);
-void rsz_set_in_pix_format(unsigned char y_c);
-int config_rsz_hw(struct vpfe_resizer_device *resizer,
- struct resizer_params *config);
-void ipipe_set_d2f_regs(void __iomem *base_addr, unsigned int id,
- struct vpfe_ipipe_nf *noise_filter);
-void ipipe_set_rgb2rgb_regs(void __iomem *base_addr, unsigned int id,
- struct vpfe_ipipe_rgb2rgb *rgb);
-void ipipe_set_yuv422_conv_regs(void __iomem *base_addr,
- struct vpfe_ipipe_yuv422_conv *conv);
-void ipipe_set_lum_adj_regs(void __iomem *base_addr,
- struct ipipe_lum_adj *lum_adj);
-void ipipe_set_rgb2ycbcr_regs(void __iomem *base_addr,
- struct vpfe_ipipe_rgb2yuv *yuv);
-void ipipe_set_lutdpc_regs(void __iomem *base_addr,
- void __iomem *isp5_base_addr, struct vpfe_ipipe_lutdpc *lutdpc);
-void ipipe_set_otfdpc_regs(void __iomem *base_addr,
- struct vpfe_ipipe_otfdpc *otfdpc);
-void ipipe_set_3d_lut_regs(void __iomem *base_addr,
- void __iomem *isp5_base_addr, struct vpfe_ipipe_3d_lut *lut_3d);
-void ipipe_set_gamma_regs(void __iomem *base_addr,
- void __iomem *isp5_base_addr, struct vpfe_ipipe_gamma *gamma);
-void ipipe_set_ee_regs(void __iomem *base_addr,
- void __iomem *isp5_base_addr, struct vpfe_ipipe_yee *ee);
-void ipipe_set_gbce_regs(void __iomem *base_addr,
- void __iomem *isp5_base_addr, struct vpfe_ipipe_gbce *gbce);
-void ipipe_set_gic_regs(void __iomem *base_addr, struct vpfe_ipipe_gic *gic);
-void ipipe_set_cfa_regs(void __iomem *base_addr, struct vpfe_ipipe_cfa *cfa);
-void ipipe_set_car_regs(void __iomem *base_addr, struct vpfe_ipipe_car *car);
-void ipipe_set_cgs_regs(void __iomem *base_addr, struct vpfe_ipipe_cgs *cgs);
-void ipipe_set_wb_regs(void __iomem *base_addr, struct vpfe_ipipe_wb *wb);
-
-#endif /* _DAVINCI_VPFE_DM365_IPIPE_HW_H */
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
deleted file mode 100644
index 51d4cd1bdb97..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
+++ /dev/null
@@ -1,1070 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#include "dm365_ipipeif.h"
-#include "vpfe_mc_capture.h"
-
-static const unsigned int ipipeif_input_fmts[] = {
- MEDIA_BUS_FMT_UYVY8_2X8,
- MEDIA_BUS_FMT_SGRBG12_1X12,
- MEDIA_BUS_FMT_Y8_1X8,
- MEDIA_BUS_FMT_UV8_1X8,
- MEDIA_BUS_FMT_YDYUYDYV8_1X16,
- MEDIA_BUS_FMT_SBGGR8_1X8,
-};
-
-static const unsigned int ipipeif_output_fmts[] = {
- MEDIA_BUS_FMT_UYVY8_2X8,
- MEDIA_BUS_FMT_SGRBG12_1X12,
- MEDIA_BUS_FMT_Y8_1X8,
- MEDIA_BUS_FMT_UV8_1X8,
- MEDIA_BUS_FMT_YDYUYDYV8_1X16,
- MEDIA_BUS_FMT_SBGGR8_1X8,
- MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
- MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
-};
-
-static int
-ipipeif_get_pack_mode(u32 in_pix_fmt)
-{
- switch (in_pix_fmt) {
- case MEDIA_BUS_FMT_SBGGR8_1X8:
- case MEDIA_BUS_FMT_Y8_1X8:
- case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
- case MEDIA_BUS_FMT_UV8_1X8:
- return IPIPEIF_5_1_PACK_8_BIT;
-
- case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
- return IPIPEIF_5_1_PACK_8_BIT_A_LAW;
-
- case MEDIA_BUS_FMT_SGRBG12_1X12:
- return IPIPEIF_5_1_PACK_16_BIT;
-
- case MEDIA_BUS_FMT_SBGGR12_1X12:
- return IPIPEIF_5_1_PACK_12_BIT;
-
- default:
- return IPIPEIF_5_1_PACK_16_BIT;
- }
-}
-
-static inline u32 ipipeif_read(void __iomem *addr, u32 offset)
-{
- return readl(addr + offset);
-}
-
-static inline void ipipeif_write(u32 val, void __iomem *addr, u32 offset)
-{
- writel(val, addr + offset);
-}
-
-static void ipipeif_config_dpc(void __iomem *addr, struct ipipeif_dpc *dpc)
-{
- u32 val = 0;
-
- if (dpc->en) {
- val = (dpc->en & 1) << IPIPEIF_DPC2_EN_SHIFT;
- val |= dpc->thr & IPIPEIF_DPC2_THR_MASK;
- }
- ipipeif_write(val, addr, IPIPEIF_DPC2);
-}
-
-#define IPIPEIF_MODE_CONTINUOUS 0
-#define IPIPEIF_MODE_ONE_SHOT 1
-
-static int get_oneshot_mode(enum ipipeif_input_entity input)
-{
- if (input == IPIPEIF_INPUT_MEMORY)
- return IPIPEIF_MODE_ONE_SHOT;
- if (input == IPIPEIF_INPUT_ISIF)
- return IPIPEIF_MODE_CONTINUOUS;
-
- return -EINVAL;
-}
-
-static int
-ipipeif_get_cfg_src1(struct vpfe_ipipeif_device *ipipeif)
-{
- struct v4l2_mbus_framefmt *informat;
-
- informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
- if (ipipeif->input == IPIPEIF_INPUT_MEMORY &&
- (informat->code == MEDIA_BUS_FMT_Y8_1X8 ||
- informat->code == MEDIA_BUS_FMT_UV8_1X8))
- return IPIPEIF_CCDC;
-
- return IPIPEIF_SRC1_PARALLEL_PORT;
-}
-
-static int
-ipipeif_get_data_shift(struct vpfe_ipipeif_device *ipipeif)
-{
- struct v4l2_mbus_framefmt *informat;
-
- informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
-
- switch (informat->code) {
- case MEDIA_BUS_FMT_SGRBG12_1X12:
- return IPIPEIF_5_1_BITS11_0;
-
- case MEDIA_BUS_FMT_Y8_1X8:
- case MEDIA_BUS_FMT_UV8_1X8:
- return IPIPEIF_5_1_BITS11_0;
-
- default:
- return IPIPEIF_5_1_BITS7_0;
- }
-}
-
-static enum ipipeif_input_source
-ipipeif_get_source(struct vpfe_ipipeif_device *ipipeif)
-{
- struct v4l2_mbus_framefmt *informat;
-
- informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
- if (ipipeif->input == IPIPEIF_INPUT_ISIF)
- return IPIPEIF_CCDC;
-
- if (informat->code == MEDIA_BUS_FMT_UYVY8_2X8)
- return IPIPEIF_SDRAM_YUV;
-
- return IPIPEIF_SDRAM_RAW;
-}
-
-void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif)
-{
- struct vpfe_video_device *video_in = &ipipeif->video_in;
-
- if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
- return;
-
- spin_lock(&video_in->dma_queue_lock);
- vpfe_video_process_buffer_complete(video_in);
- video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
- vpfe_video_schedule_next_buffer(video_in);
- spin_unlock(&video_in->dma_queue_lock);
-}
-
-int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
-
- return ipipeif->config.decimation;
-}
-
-int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
-
- return ipipeif->config.rsz;
-}
-
-#define RD_DATA_15_2 0x7
-
-/*
- * ipipeif_hw_setup() - This function sets up IPIPEIF
- * @sd: pointer to v4l2 subdev structure
- * return -EINVAL or zero on success
- */
-static int ipipeif_hw_setup(struct v4l2_subdev *sd)
-{
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *informat, *outformat;
- struct ipipeif_params params = ipipeif->config;
- enum ipipeif_input_source ipipeif_source;
- u32 isif_port_if;
- void __iomem *ipipeif_base_addr;
- unsigned long val;
- int data_shift;
- int pack_mode;
- int source1;
- int tmp;
-
- ipipeif_base_addr = ipipeif->ipipeif_base_addr;
-
- /* Enable clock to IPIPEIF and IPIPE */
- vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
-
- informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
- outformat = &ipipeif->formats[IPIPEIF_PAD_SOURCE];
-
- /* Combine all the fields to make CFG1 register of IPIPEIF */
- tmp = val = get_oneshot_mode(ipipeif->input);
- if (tmp < 0) {
- dev_err(&sd->devnode->dev, "ipipeif: links setup required");
- return -EINVAL;
- }
- val <<= ONESHOT_SHIFT;
-
- ipipeif_source = ipipeif_get_source(ipipeif);
- val |= ipipeif_source << INPSRC_SHIFT;
-
- val |= params.clock_select << CLKSEL_SHIFT;
- val |= params.avg_filter << AVGFILT_SHIFT;
- val |= params.decimation << DECIM_SHIFT;
-
- pack_mode = ipipeif_get_pack_mode(informat->code);
- val |= pack_mode << PACK8IN_SHIFT;
-
- source1 = ipipeif_get_cfg_src1(ipipeif);
- val |= source1 << INPSRC1_SHIFT;
-
- data_shift = ipipeif_get_data_shift(ipipeif);
- if (ipipeif_source != IPIPEIF_SDRAM_YUV)
- val |= data_shift << DATASFT_SHIFT;
- else
- val &= ~(RD_DATA_15_2 << DATASFT_SHIFT);
-
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG1);
-
- switch (ipipeif_source) {
- case IPIPEIF_CCDC:
- ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
- break;
-
- case IPIPEIF_SDRAM_RAW:
- case IPIPEIF_CCDC_DARKFM:
- ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
- /* fall through */
- case IPIPEIF_SDRAM_YUV:
- val |= data_shift << DATASFT_SHIFT;
- ipipeif_write(params.ppln, ipipeif_base_addr, IPIPEIF_PPLN);
- ipipeif_write(params.lpfr, ipipeif_base_addr, IPIPEIF_LPFR);
- ipipeif_write(informat->width, ipipeif_base_addr, IPIPEIF_HNUM);
- ipipeif_write(informat->height,
- ipipeif_base_addr, IPIPEIF_VNUM);
- break;
-
- default:
- return -EINVAL;
- }
-
- /*check if decimation is enable or not */
- if (params.decimation)
- ipipeif_write(params.rsz, ipipeif_base_addr, IPIPEIF_RSZ);
-
- /* Setup sync alignment and initial rsz position */
- val = params.if_5_1.align_sync & 1;
- val <<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT;
- val |= params.if_5_1.rsz_start & IPIPEIF_INIRSZ_MASK;
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_INIRSZ);
- isif_port_if = informat->code;
-
- if (isif_port_if == MEDIA_BUS_FMT_Y8_1X8)
- isif_port_if = MEDIA_BUS_FMT_YUYV8_1X16;
- else if (isif_port_if == MEDIA_BUS_FMT_UV8_1X8)
- isif_port_if = MEDIA_BUS_FMT_SGRBG12_1X12;
-
- /* Enable DPCM decompression */
- switch (ipipeif_source) {
- case IPIPEIF_SDRAM_RAW:
- val = 0;
- if (outformat->code == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) {
- val = 1;
- val |= (IPIPEIF_DPCM_8BIT_10BIT & 1) <<
- IPIPEIF_DPCM_BITS_SHIFT;
- val |= (ipipeif->dpcm_predictor & 1) <<
- IPIPEIF_DPCM_PRED_SHIFT;
- }
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DPCM);
-
- /* set DPC */
- ipipeif_config_dpc(ipipeif_base_addr, &params.if_5_1.dpc);
-
- ipipeif_write(params.if_5_1.clip,
- ipipeif_base_addr, IPIPEIF_OCLIP);
-
- /* fall through for SDRAM YUV mode */
- /* configure CFG2 */
- val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CFG2);
- switch (isif_port_if) {
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_Y8_1X8:
- clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val);
- set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val);
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
- break;
-
- default:
- clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val);
- clear_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val);
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
- break;
- }
- /* fall through */
-
- case IPIPEIF_SDRAM_YUV:
- /* Set clock divider */
- if (params.clock_select == IPIPEIF_SDRAM_CLK) {
- val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CLKDIV);
- val |= (params.if_5_1.clk_div.m - 1) <<
- IPIPEIF_CLKDIV_M_SHIFT;
- val |= (params.if_5_1.clk_div.n - 1);
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CLKDIV);
- }
- break;
-
- case IPIPEIF_CCDC:
- case IPIPEIF_CCDC_DARKFM:
- /* set DPC */
- ipipeif_config_dpc(ipipeif_base_addr, &params.if_5_1.dpc);
-
- /* Set DF gain & threshold control */
- val = 0;
- if (params.if_5_1.df_gain_en) {
- val = params.if_5_1.df_gain_thr &
- IPIPEIF_DF_GAIN_THR_MASK;
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGTH);
- val = (params.if_5_1.df_gain_en & 1) <<
- IPIPEIF_DF_GAIN_EN_SHIFT;
- val |= params.if_5_1.df_gain &
- IPIPEIF_DF_GAIN_MASK;
- }
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGVL);
- /* configure CFG2 */
- val = VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_HDPOL_SHIFT;
- val |= VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_VDPOL_SHIFT;
-
- switch (isif_port_if) {
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YUYV10_1X20:
- clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val);
- set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val);
- break;
-
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_Y8_1X8:
- case MEDIA_BUS_FMT_YUYV10_2X10:
- set_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val);
- set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val);
- val |= IPIPEIF_CBCR_Y << IPIPEIF_CFG2_YUV8P_SHIFT;
- break;
-
- default:
- /* Bayer */
- ipipeif_write(params.if_5_1.clip, ipipeif_base_addr,
- IPIPEIF_OCLIP);
- }
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int
-ipipeif_set_config(struct v4l2_subdev *sd, struct ipipeif_params *config)
-{
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
- struct device *dev = ipipeif->subdev.v4l2_dev->dev;
-
- if (!config) {
- dev_err(dev, "Invalid configuration pointer\n");
- return -EINVAL;
- }
-
- ipipeif->config.clock_select = config->clock_select;
- ipipeif->config.ppln = config->ppln;
- ipipeif->config.lpfr = config->lpfr;
- ipipeif->config.rsz = config->rsz;
- ipipeif->config.decimation = config->decimation;
- if (ipipeif->config.decimation &&
- (ipipeif->config.rsz < IPIPEIF_RSZ_MIN ||
- ipipeif->config.rsz > IPIPEIF_RSZ_MAX)) {
- dev_err(dev, "rsz range is %d to %d\n",
- IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
- return -EINVAL;
- }
-
- ipipeif->config.avg_filter = config->avg_filter;
-
- ipipeif->config.if_5_1.df_gain_thr = config->if_5_1.df_gain_thr;
- ipipeif->config.if_5_1.df_gain = config->if_5_1.df_gain;
- ipipeif->config.if_5_1.df_gain_en = config->if_5_1.df_gain_en;
-
- ipipeif->config.if_5_1.rsz_start = config->if_5_1.rsz_start;
- ipipeif->config.if_5_1.align_sync = config->if_5_1.align_sync;
- ipipeif->config.if_5_1.clip = config->if_5_1.clip;
-
- ipipeif->config.if_5_1.dpc.en = config->if_5_1.dpc.en;
- ipipeif->config.if_5_1.dpc.thr = config->if_5_1.dpc.thr;
-
- ipipeif->config.if_5_1.clk_div.m = config->if_5_1.clk_div.m;
- ipipeif->config.if_5_1.clk_div.n = config->if_5_1.clk_div.n;
-
- return 0;
-}
-
-static int
-ipipeif_get_config(struct v4l2_subdev *sd, void *arg)
-{
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
- struct ipipeif_params *config = arg;
- struct device *dev = ipipeif->subdev.v4l2_dev->dev;
-
- if (!arg) {
- dev_err(dev, "Invalid configuration pointer\n");
- return -EINVAL;
- }
-
- config->clock_select = ipipeif->config.clock_select;
- config->ppln = ipipeif->config.ppln;
- config->lpfr = ipipeif->config.lpfr;
- config->rsz = ipipeif->config.rsz;
- config->decimation = ipipeif->config.decimation;
- config->avg_filter = ipipeif->config.avg_filter;
-
- config->if_5_1.df_gain_thr = ipipeif->config.if_5_1.df_gain_thr;
- config->if_5_1.df_gain = ipipeif->config.if_5_1.df_gain;
- config->if_5_1.df_gain_en = ipipeif->config.if_5_1.df_gain_en;
-
- config->if_5_1.rsz_start = ipipeif->config.if_5_1.rsz_start;
- config->if_5_1.align_sync = ipipeif->config.if_5_1.align_sync;
- config->if_5_1.clip = ipipeif->config.if_5_1.clip;
-
- config->if_5_1.dpc.en = ipipeif->config.if_5_1.dpc.en;
- config->if_5_1.dpc.thr = ipipeif->config.if_5_1.dpc.thr;
-
- config->if_5_1.clk_div.m = ipipeif->config.if_5_1.clk_div.m;
- config->if_5_1.clk_div.n = ipipeif->config.if_5_1.clk_div.n;
-
- return 0;
-}
-
-/*
- * ipipeif_ioctl() - Handle ipipeif module private ioctl's
- * @sd: pointer to v4l2 subdev structure
- * @cmd: configuration command
- * @arg: configuration argument
- */
-static long ipipeif_ioctl(struct v4l2_subdev *sd,
- unsigned int cmd, void *arg)
-{
- struct ipipeif_params *config = arg;
- int ret = -ENOIOCTLCMD;
-
- switch (cmd) {
- case VIDIOC_VPFE_IPIPEIF_S_CONFIG:
- ret = ipipeif_set_config(sd, config);
- break;
-
- case VIDIOC_VPFE_IPIPEIF_G_CONFIG:
- ret = ipipeif_get_config(sd, arg);
- break;
- }
- return ret;
-}
-
-/*
- * ipipeif_s_ctrl() - Handle set control subdev method
- * @ctrl: pointer to v4l2 control structure
- */
-static int ipipeif_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct vpfe_ipipeif_device *ipipeif =
- container_of(ctrl->handler, struct vpfe_ipipeif_device, ctrls);
-
- switch (ctrl->id) {
- case VPFE_CID_DPCM_PREDICTOR:
- ipipeif->dpcm_predictor = ctrl->val;
- break;
-
- case V4L2_CID_GAIN:
- ipipeif->gain = ctrl->val;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-#define ENABLE_IPIPEIF 0x1
-
-void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
- void __iomem *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
- unsigned char val;
-
- if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
- return;
-
- do {
- val = ipipeif_read(ipipeif_base_addr, IPIPEIF_ENABLE);
- } while (val & 0x1);
-
- ipipeif_write(ENABLE_IPIPEIF, ipipeif_base_addr, IPIPEIF_ENABLE);
-}
-
-/*
- * ipipeif_set_stream() - Enable/Disable streaming on ipipeif subdev
- * @sd: pointer to v4l2 subdev structure
- * @enable: 1 == Enable, 0 == Disable
- */
-static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
- struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
- int ret = 0;
-
- if (!enable)
- return ret;
-
- ret = ipipeif_hw_setup(sd);
- if (!ret)
- vpfe_ipipeif_enable(vpfe_dev);
-
- return ret;
-}
-
-/*
- * ipipeif_enum_mbus_code() - Handle pixel format enumeration
- * @sd: pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
- * @code: pointer to v4l2_subdev_mbus_code_enum structure
- * return -EINVAL or zero on success
- */
-static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- switch (code->pad) {
- case IPIPEIF_PAD_SINK:
- if (code->index >= ARRAY_SIZE(ipipeif_input_fmts))
- return -EINVAL;
-
- code->code = ipipeif_input_fmts[code->index];
- break;
-
- case IPIPEIF_PAD_SOURCE:
- if (code->index >= ARRAY_SIZE(ipipeif_output_fmts))
- return -EINVAL;
-
- code->code = ipipeif_output_fmts[code->index];
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * ipipeif_get_format() - Handle get format by pads subdev method
- * @sd: pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- */
-static int
-ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- fmt->format = ipipeif->formats[fmt->pad];
- else
- fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad));
-
- return 0;
-}
-
-#define MIN_OUT_WIDTH 32
-#define MIN_OUT_HEIGHT 32
-
-/*
- * ipipeif_try_format() - Handle try format by pad subdev method
- * @ipipeif: VPFE ipipeif device.
- * @cfg: V4L2 subdev pad config
- * @pad: pad num.
- * @fmt: pointer to v4l2 format structure.
- * @which : wanted subdev format
- */
-static void
-ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
- struct v4l2_mbus_framefmt *fmt,
- enum v4l2_subdev_format_whence which)
-{
- unsigned int max_out_height;
- unsigned int max_out_width;
- unsigned int i;
-
- max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
- max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
-
- if (pad == IPIPEIF_PAD_SINK) {
- for (i = 0; i < ARRAY_SIZE(ipipeif_input_fmts); i++)
- if (fmt->code == ipipeif_input_fmts[i])
- break;
-
- /* If not found, use SBGGR10 as default */
- if (i >= ARRAY_SIZE(ipipeif_input_fmts))
- fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12;
- } else if (pad == IPIPEIF_PAD_SOURCE) {
- for (i = 0; i < ARRAY_SIZE(ipipeif_output_fmts); i++)
- if (fmt->code == ipipeif_output_fmts[i])
- break;
-
- /* If not found, use UYVY as default */
- if (i >= ARRAY_SIZE(ipipeif_output_fmts))
- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
- }
-
- fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
- fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height);
-}
-
-static int
-ipipeif_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt format;
-
- if (fse->index != 0)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = 1;
- format.height = 1;
- ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
- fse->min_width = format.width;
- fse->min_height = format.height;
-
- if (format.code != fse->code)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = -1;
- format.height = -1;
- ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
- fse->max_width = format.width;
- fse->max_height = format.height;
-
- return 0;
-}
-
-/*
- * __ipipeif_get_format() - helper function for getting ipipeif format
- * @ipipeif: pointer to ipipeif private structure.
- * @cfg: V4L2 subdev pad config
- * @pad: pad number.
- * @which: wanted subdev format.
- *
- */
-static struct v4l2_mbus_framefmt *
-__ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad);
-
- return &ipipeif->formats[pad];
-}
-
-/*
- * ipipeif_set_format() - Handle set format by pads subdev method
- * @sd: pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int
-ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which);
- if (!format)
- return -EINVAL;
-
- ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- return 0;
-
- if (fmt->pad == IPIPEIF_PAD_SINK &&
- ipipeif->input != IPIPEIF_INPUT_NONE)
- ipipeif->formats[fmt->pad] = fmt->format;
- else if (fmt->pad == IPIPEIF_PAD_SOURCE &&
- ipipeif->output != IPIPEIF_OUTPUT_NONE)
- ipipeif->formats[fmt->pad] = fmt->format;
- else
- return -EINVAL;
-
- return 0;
-}
-
-static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif)
-{
-#define WIDTH_I 640
-#define HEIGHT_I 480
-
- const struct ipipeif_params ipipeif_defaults = {
- .clock_select = IPIPEIF_SDRAM_CLK,
- .ppln = WIDTH_I + 8,
- .lpfr = HEIGHT_I + 10,
- .rsz = 16, /* resize ratio 16/rsz */
- .decimation = IPIPEIF_DECIMATION_OFF,
- .avg_filter = IPIPEIF_AVG_OFF,
- .if_5_1 = {
- .clk_div = {
- .m = 1, /* clock = sdram clock * (m/n) */
- .n = 6
- },
- .clip = 4095,
- },
- };
- memcpy(&ipipeif->config, &ipipeif_defaults,
- sizeof(struct ipipeif_params));
-}
-
-/*
- * ipipeif_init_formats() - Initialize formats on all pads
- * @sd: VPFE ipipeif V4L2 subdevice
- * @fh: V4L2 subdev file handle
- *
- * Initialize all pad formats with default values. Try formats are initialized
- * on the file handle.
- */
-static int
-ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
- struct v4l2_subdev_format format;
-
- memset(&format, 0, sizeof(format));
- format.pad = IPIPEIF_PAD_SINK;
- format.which = V4L2_SUBDEV_FORMAT_TRY;
- format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
- format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
- format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
- ipipeif_set_format(sd, fh->pad, &format);
-
- memset(&format, 0, sizeof(format));
- format.pad = IPIPEIF_PAD_SOURCE;
- format.which = V4L2_SUBDEV_FORMAT_TRY;
- format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
- format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
- format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
- ipipeif_set_format(sd, fh->pad, &format);
-
- ipipeif_set_default_config(ipipeif);
-
- return 0;
-}
-
-/*
- * ipipeif_video_in_queue() - ipipeif video in queue
- * @vpfe_dev: vpfe device pointer
- * @addr: buffer address
- */
-static int
-ipipeif_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
-{
- struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
- void __iomem *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
- unsigned int adofs;
- u32 val;
-
- if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
- return -EINVAL;
-
- switch (ipipeif->formats[IPIPEIF_PAD_SINK].code) {
- case MEDIA_BUS_FMT_Y8_1X8:
- case MEDIA_BUS_FMT_UV8_1X8:
- case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
- adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width;
- break;
-
- default:
- adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width << 1;
- break;
- }
-
- /* adjust the line len to be a multiple of 32 */
- adofs += 31;
- adofs &= ~0x1f;
- val = (adofs >> 5) & IPIPEIF_ADOFS_LSB_MASK;
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADOFS);
-
- /* lower sixteen bit */
- val = (addr >> IPIPEIF_ADDRL_SHIFT) & IPIPEIF_ADDRL_MASK;
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRL);
-
- /* upper next seven bit */
- val = (addr >> IPIPEIF_ADDRU_SHIFT) & IPIPEIF_ADDRU_MASK;
- ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRU);
-
- return 0;
-}
-
-/* subdev core operations */
-static const struct v4l2_subdev_core_ops ipipeif_v4l2_core_ops = {
- .ioctl = ipipeif_ioctl,
-};
-
-static const struct v4l2_ctrl_ops ipipeif_ctrl_ops = {
- .s_ctrl = ipipeif_s_ctrl,
-};
-
-static const struct v4l2_ctrl_config vpfe_ipipeif_dpcm_pred = {
- .ops = &ipipeif_ctrl_ops,
- .id = VPFE_CID_DPCM_PREDICTOR,
- .name = "DPCM Predictor",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = 1,
- .step = 1,
- .def = 0,
-};
-
-/* subdev file operations */
-static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = {
- .open = ipipeif_init_formats,
-};
-
-/* subdev video operations */
-static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = {
- .s_stream = ipipeif_set_stream,
-};
-
-/* subdev pad operations */
-static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = {
- .enum_mbus_code = ipipeif_enum_mbus_code,
- .enum_frame_size = ipipeif_enum_frame_size,
- .get_fmt = ipipeif_get_format,
- .set_fmt = ipipeif_set_format,
-};
-
-/* subdev operations */
-static const struct v4l2_subdev_ops ipipeif_v4l2_ops = {
- .core = &ipipeif_v4l2_core_ops,
- .video = &ipipeif_v4l2_video_ops,
- .pad = &ipipeif_v4l2_pad_ops,
-};
-
-static const struct vpfe_video_operations video_in_ops = {
- .queue = ipipeif_video_in_queue,
-};
-
-static int
-ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
- struct vpfe_device *vpfe = to_vpfe_device(ipipeif);
- unsigned int index = local->index;
-
- /* FIXME: this is actually a hack! */
- if (is_media_entity_v4l2_subdev(remote->entity))
- index |= 2 << 16;
-
- switch (index) {
- case IPIPEIF_PAD_SINK:
- /* Single shot mode */
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- ipipeif->input = IPIPEIF_INPUT_NONE;
- break;
- }
- ipipeif->input = IPIPEIF_INPUT_MEMORY;
- break;
-
- case IPIPEIF_PAD_SINK | 2 << 16:
- /* read from isif */
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- ipipeif->input = IPIPEIF_INPUT_NONE;
- break;
- }
- if (ipipeif->input != IPIPEIF_INPUT_NONE)
- return -EBUSY;
-
- ipipeif->input = IPIPEIF_INPUT_ISIF;
- break;
-
- case IPIPEIF_PAD_SOURCE | 2 << 16:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- ipipeif->output = IPIPEIF_OUTPUT_NONE;
- break;
- }
- if (remote->entity == &vpfe->vpfe_ipipe.subdev.entity)
- /* connencted to ipipe */
- ipipeif->output = IPIPEIF_OUTPUT_IPIPE;
- else if (remote->entity == &vpfe->vpfe_resizer.crop_resizer.subdev.entity)
- /* connected to resizer */
- ipipeif->output = IPIPEIF_OUTPUT_RESIZER;
- else
- return -EINVAL;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const struct media_entity_operations ipipeif_media_ops = {
- .link_setup = ipipeif_link_setup,
-};
-
-/*
- * vpfe_ipipeif_unregister_entities() - Unregister entity
- * @ipipeif - pointer to ipipeif subdevice structure.
- */
-void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif)
-{
- /* unregister video device */
- vpfe_video_unregister(&ipipeif->video_in);
-
- /* unregister subdev */
- v4l2_device_unregister_subdev(&ipipeif->subdev);
- /* cleanup entity */
- media_entity_cleanup(&ipipeif->subdev.entity);
-}
-
-int
-vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif,
- struct v4l2_device *vdev)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
- unsigned int flags;
- int ret;
-
- /* Register the subdev */
- ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev);
- if (ret < 0)
- return ret;
-
- ret = vpfe_video_register(&ipipeif->video_in, vdev);
- if (ret) {
- pr_err("Failed to register ipipeif video-in device\n");
- goto fail;
- }
- ipipeif->video_in.vpfe_dev = vpfe_dev;
-
- flags = 0;
- ret = media_create_pad_link(&ipipeif->video_in.video_dev.entity, 0,
- &ipipeif->subdev.entity, 0, flags);
- if (ret < 0)
- goto fail;
-
- return 0;
-fail:
- v4l2_device_unregister_subdev(&ipipeif->subdev);
-
- return ret;
-}
-
-#define IPIPEIF_GAIN_HIGH 0x3ff
-#define IPIPEIF_DEFAULT_GAIN 0x200
-
-int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif,
- struct platform_device *pdev)
-{
- struct v4l2_subdev *sd = &ipipeif->subdev;
- struct media_pad *pads = &ipipeif->pads[0];
- struct media_entity *me = &sd->entity;
- static resource_size_t res_len;
- struct resource *res;
- int ret;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
- if (!res)
- return -ENOENT;
-
- res_len = resource_size(res);
- res = request_mem_region(res->start, res_len, res->name);
- if (!res)
- return -EBUSY;
-
- ipipeif->ipipeif_base_addr = ioremap_nocache(res->start, res_len);
- if (!ipipeif->ipipeif_base_addr) {
- ret = -EBUSY;
- goto fail;
- }
-
- v4l2_subdev_init(sd, &ipipeif_v4l2_ops);
-
- sd->internal_ops = &ipipeif_v4l2_internal_ops;
- strscpy(sd->name, "DAVINCI IPIPEIF", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
-
- v4l2_set_subdevdata(sd, ipipeif);
-
- sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
- pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[IPIPEIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ipipeif->input = IPIPEIF_INPUT_NONE;
- ipipeif->output = IPIPEIF_OUTPUT_NONE;
- me->ops = &ipipeif_media_ops;
-
- ret = media_entity_pads_init(me, IPIPEIF_NUM_PADS, pads);
- if (ret)
- goto fail;
-
- v4l2_ctrl_handler_init(&ipipeif->ctrls, 2);
- v4l2_ctrl_new_std(&ipipeif->ctrls, &ipipeif_ctrl_ops,
- V4L2_CID_GAIN, 0,
- IPIPEIF_GAIN_HIGH, 1, IPIPEIF_DEFAULT_GAIN);
- v4l2_ctrl_new_custom(&ipipeif->ctrls, &vpfe_ipipeif_dpcm_pred, NULL);
- v4l2_ctrl_handler_setup(&ipipeif->ctrls);
- sd->ctrl_handler = &ipipeif->ctrls;
-
- ipipeif->video_in.ops = &video_in_ops;
- ipipeif->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- ret = vpfe_video_init(&ipipeif->video_in, "IPIPEIF");
- if (ret) {
- pr_err("Failed to init IPIPEIF video-in device\n");
- goto fail;
- }
- ipipeif_set_default_config(ipipeif);
- return 0;
-fail:
- release_mem_region(res->start, res_len);
- return ret;
-}
-
-void
-vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif,
- struct platform_device *pdev)
-{
- struct resource *res;
-
- v4l2_ctrl_handler_free(&ipipeif->ctrls);
- iounmap(ipipeif->ipipeif_base_addr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
- if (res)
- release_mem_region(res->start, resource_size(res));
-
-}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h
deleted file mode 100644
index 4d126fc871f3..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_DM365_IPIPEIF_H
-#define _DAVINCI_VPFE_DM365_IPIPEIF_H
-
-#include <linux/platform_device.h>
-
-#include <media/davinci/vpss.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-subdev.h>
-
-#include "dm365_ipipeif_user.h"
-#include "vpfe_video.h"
-
-/* IPIPE base specific types */
-enum ipipeif_data_shift {
- IPIPEIF_BITS15_2 = 0,
- IPIPEIF_BITS14_1 = 1,
- IPIPEIF_BITS13_0 = 2,
- IPIPEIF_BITS12_0 = 3,
- IPIPEIF_BITS11_0 = 4,
- IPIPEIF_BITS10_0 = 5,
- IPIPEIF_BITS9_0 = 6,
-};
-
-enum ipipeif_clkdiv {
- IPIPEIF_DIVIDE_HALF = 0,
- IPIPEIF_DIVIDE_THIRD = 1,
- IPIPEIF_DIVIDE_FOURTH = 2,
- IPIPEIF_DIVIDE_FIFTH = 3,
- IPIPEIF_DIVIDE_SIXTH = 4,
- IPIPEIF_DIVIDE_EIGHTH = 5,
- IPIPEIF_DIVIDE_SIXTEENTH = 6,
- IPIPEIF_DIVIDE_THIRTY = 7,
-};
-
-enum ipipeif_pack_mode {
- IPIPEIF_PACK_16_BIT = 0,
- IPIPEIF_PACK_8_BIT = 1,
-};
-
-enum ipipeif_5_1_pack_mode {
- IPIPEIF_5_1_PACK_16_BIT = 0,
- IPIPEIF_5_1_PACK_8_BIT = 1,
- IPIPEIF_5_1_PACK_8_BIT_A_LAW = 2,
- IPIPEIF_5_1_PACK_12_BIT = 3
-};
-
-enum ipipeif_input_source {
- IPIPEIF_CCDC = 0,
- IPIPEIF_SDRAM_RAW = 1,
- IPIPEIF_CCDC_DARKFM = 2,
- IPIPEIF_SDRAM_YUV = 3,
-};
-
-enum ipipeif_ialaw {
- IPIPEIF_ALAW_OFF = 0,
- IPIPEIF_ALAW_ON = 1,
-};
-
-enum ipipeif_input_src1 {
- IPIPEIF_SRC1_PARALLEL_PORT = 0,
- IPIPEIF_SRC1_SDRAM_RAW = 1,
- IPIPEIF_SRC1_ISIF_DARKFM = 2,
- IPIPEIF_SRC1_SDRAM_YUV = 3,
-};
-
-enum ipipeif_dfs_dir {
- IPIPEIF_PORT_MINUS_SDRAM = 0,
- IPIPEIF_SDRAM_MINUS_PORT = 1,
-};
-
-enum ipipeif_chroma_phase {
- IPIPEIF_CBCR_Y = 0,
- IPIPEIF_Y_CBCR = 1,
-};
-
-enum ipipeif_dpcm_type {
- IPIPEIF_DPCM_8BIT_10BIT = 0,
- IPIPEIF_DPCM_8BIT_12BIT = 1,
-};
-
-/* data shift for IPIPE 5.1 */
-enum ipipeif_5_1_data_shift {
- IPIPEIF_5_1_BITS11_0 = 0,
- IPIPEIF_5_1_BITS10_0 = 1,
- IPIPEIF_5_1_BITS9_0 = 2,
- IPIPEIF_5_1_BITS8_0 = 3,
- IPIPEIF_5_1_BITS7_0 = 4,
- IPIPEIF_5_1_BITS15_4 = 5,
-};
-
-#define IPIPEIF_PAD_SINK 0
-#define IPIPEIF_PAD_SOURCE 1
-
-#define IPIPEIF_NUM_PADS 2
-
-enum ipipeif_input_entity {
- IPIPEIF_INPUT_NONE = 0,
- IPIPEIF_INPUT_ISIF = 1,
- IPIPEIF_INPUT_MEMORY = 2,
-};
-
-enum ipipeif_output_entity {
- IPIPEIF_OUTPUT_NONE = 0,
- IPIPEIF_OUTPUT_IPIPE = 1,
- IPIPEIF_OUTPUT_RESIZER = 2,
-};
-
-struct vpfe_ipipeif_device {
- struct v4l2_subdev subdev;
- struct media_pad pads[IPIPEIF_NUM_PADS];
- struct v4l2_mbus_framefmt formats[IPIPEIF_NUM_PADS];
- enum ipipeif_input_entity input;
- unsigned int output;
- struct vpfe_video_device video_in;
- struct v4l2_ctrl_handler ctrls;
- void __iomem *ipipeif_base_addr;
- struct ipipeif_params config;
- int dpcm_predictor;
- int gain;
-};
-
-/* IPIPEIF Register Offsets from the base address */
-#define IPIPEIF_ENABLE 0x00
-#define IPIPEIF_CFG1 0x04
-#define IPIPEIF_PPLN 0x08
-#define IPIPEIF_LPFR 0x0c
-#define IPIPEIF_HNUM 0x10
-#define IPIPEIF_VNUM 0x14
-#define IPIPEIF_ADDRU 0x18
-#define IPIPEIF_ADDRL 0x1c
-#define IPIPEIF_ADOFS 0x20
-#define IPIPEIF_RSZ 0x24
-#define IPIPEIF_GAIN 0x28
-
-/* Below registers are available only on IPIPE 5.1 */
-#define IPIPEIF_DPCM 0x2c
-#define IPIPEIF_CFG2 0x30
-#define IPIPEIF_INIRSZ 0x34
-#define IPIPEIF_OCLIP 0x38
-#define IPIPEIF_DTUDF 0x3c
-#define IPIPEIF_CLKDIV 0x40
-#define IPIPEIF_DPC1 0x44
-#define IPIPEIF_DPC2 0x48
-#define IPIPEIF_DFSGVL 0x4c
-#define IPIPEIF_DFSGTH 0x50
-#define IPIPEIF_RSZ3A 0x54
-#define IPIPEIF_INIRSZ3A 0x58
-#define IPIPEIF_RSZ_MIN 16
-#define IPIPEIF_RSZ_MAX 112
-#define IPIPEIF_RSZ_CONST 16
-
-#define IPIPEIF_ADOFS_LSB_MASK 0x1ff
-#define IPIPEIF_ADOFS_LSB_SHIFT 5
-#define IPIPEIF_ADOFS_MSB_MASK 0x200
-#define IPIPEIF_ADDRU_MASK 0x7ff
-#define IPIPEIF_ADDRL_SHIFT 5
-#define IPIPEIF_ADDRL_MASK 0xffff
-#define IPIPEIF_ADDRU_SHIFT 21
-#define IPIPEIF_ADDRMSB_SHIFT 31
-#define IPIPEIF_ADDRMSB_LEFT_SHIFT 10
-
-/* CFG1 Masks and shifts */
-#define ONESHOT_SHIFT 0
-#define DECIM_SHIFT 1
-#define INPSRC_SHIFT 2
-#define CLKDIV_SHIFT 4
-#define AVGFILT_SHIFT 7
-#define PACK8IN_SHIFT 8
-#define IALAW_SHIFT 9
-#define CLKSEL_SHIFT 10
-#define DATASFT_SHIFT 11
-#define INPSRC1_SHIFT 14
-
-/* DPC2 */
-#define IPIPEIF_DPC2_EN_SHIFT 12
-#define IPIPEIF_DPC2_THR_MASK 0xfff
-/* Applicable for IPIPE 5.1 */
-#define IPIPEIF_DF_GAIN_EN_SHIFT 10
-#define IPIPEIF_DF_GAIN_MASK 0x3ff
-#define IPIPEIF_DF_GAIN_THR_MASK 0xfff
-/* DPCM */
-#define IPIPEIF_DPCM_BITS_SHIFT 2
-#define IPIPEIF_DPCM_PRED_SHIFT 1
-/* CFG2 */
-#define IPIPEIF_CFG2_HDPOL_SHIFT 1
-#define IPIPEIF_CFG2_VDPOL_SHIFT 2
-#define IPIPEIF_CFG2_YUV8_SHIFT 6
-#define IPIPEIF_CFG2_YUV16_SHIFT 3
-#define IPIPEIF_CFG2_YUV8P_SHIFT 7
-
-/* INIRSZ */
-#define IPIPEIF_INIRSZ_ALNSYNC_SHIFT 13
-#define IPIPEIF_INIRSZ_MASK 0x1fff
-
-/* CLKDIV */
-#define IPIPEIF_CLKDIV_M_SHIFT 8
-
-void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev);
-void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif);
-int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev);
-int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev);
-void vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif,
- struct platform_device *pdev);
-int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif,
- struct platform_device *pdev);
-int vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif,
- struct v4l2_device *vdev);
-void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif);
-
-#endif /* _DAVINCI_VPFE_DM365_IPIPEIF_H */
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h b/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h
deleted file mode 100644
index 046dbdec67d8..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_DM365_IPIPEIF_USER_H
-#define _DAVINCI_VPFE_DM365_IPIPEIF_USER_H
-
-/* clockdiv for IPIPE 5.1 */
-struct ipipeif_5_1_clkdiv {
- unsigned char m;
- unsigned char n;
-};
-
-enum ipipeif_decimation {
- IPIPEIF_DECIMATION_OFF,
- IPIPEIF_DECIMATION_ON
-};
-
-/* DPC at the if for IPIPE 5.1 */
-struct ipipeif_dpc {
- /* 0 - disable, 1 - enable */
- unsigned char en;
- /* threshold */
- unsigned short thr;
-};
-
-enum ipipeif_clock {
- IPIPEIF_PIXCEL_CLK,
- IPIPEIF_SDRAM_CLK
-};
-
-enum ipipeif_avg_filter {
- IPIPEIF_AVG_OFF,
- IPIPEIF_AVG_ON
-};
-
-struct ipipeif_5_1 {
- struct ipipeif_5_1_clkdiv clk_div;
- /* Defect pixel correction */
- struct ipipeif_dpc dpc;
- /* clipped to this value */
- unsigned short clip;
- /* Align HSync and VSync to rsz_start */
- unsigned char align_sync;
- /* resizer start position */
- unsigned int rsz_start;
- /* DF gain enable */
- unsigned char df_gain_en;
- /* DF gain value */
- unsigned short df_gain;
- /* DF gain threshold value */
- unsigned short df_gain_thr;
-};
-
-struct ipipeif_params {
- enum ipipeif_clock clock_select;
- unsigned int ppln;
- unsigned int lpfr;
- unsigned char rsz;
- enum ipipeif_decimation decimation;
- enum ipipeif_avg_filter avg_filter;
- /* IPIPE 5.1 */
- struct ipipeif_5_1 if_5_1;
-};
-
-/*
- * Private IOCTL
- * VIDIOC_VPFE_IPIPEIF_S_CONFIG: Set IPIEIF configuration
- * VIDIOC_VPFE_IPIPEIF_G_CONFIG: Get IPIEIF configuration
- */
-#define VIDIOC_VPFE_IPIPEIF_S_CONFIG \
- _IOWR('I', BASE_VIDIOC_PRIVATE + 1, struct ipipeif_params)
-#define VIDIOC_VPFE_IPIPEIF_G_CONFIG \
- _IOWR('I', BASE_VIDIOC_PRIVATE + 2, struct ipipeif_params)
-
-#endif /* _DAVINCI_VPFE_DM365_IPIPEIF_USER_H */
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c
deleted file mode 100644
index 05a997f7aa5d..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.c
+++ /dev/null
@@ -1,2097 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#include <linux/delay.h>
-#include "dm365_isif.h"
-#include "vpfe_mc_capture.h"
-
-#define MAX_WIDTH 4096
-#define MAX_HEIGHT 4096
-
-static const unsigned int isif_fmts[] = {
- MEDIA_BUS_FMT_YUYV8_2X8,
- MEDIA_BUS_FMT_UYVY8_2X8,
- MEDIA_BUS_FMT_YUYV8_1X16,
- MEDIA_BUS_FMT_YUYV10_1X20,
- MEDIA_BUS_FMT_SGRBG12_1X12,
- MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
- MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
-};
-
-#define ISIF_COLPTN_R_Ye 0x0
-#define ISIF_COLPTN_Gr_Cy 0x1
-#define ISIF_COLPTN_Gb_G 0x2
-#define ISIF_COLPTN_B_Mg 0x3
-
-#define ISIF_CCOLP_CP01_0 0
-#define ISIF_CCOLP_CP03_2 2
-#define ISIF_CCOLP_CP05_4 4
-#define ISIF_CCOLP_CP07_6 6
-#define ISIF_CCOLP_CP11_0 8
-#define ISIF_CCOLP_CP13_2 10
-#define ISIF_CCOLP_CP15_4 12
-#define ISIF_CCOLP_CP17_6 14
-
-static const u32 isif_sgrbg_pattern =
- ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP01_0 |
- ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP03_2 |
- ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP05_4 |
- ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP07_6 |
- ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP11_0 |
- ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP13_2 |
- ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP15_4 |
- ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP17_6;
-
-static const u32 isif_srggb_pattern =
- ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP01_0 |
- ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP03_2 |
- ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP05_4 |
- ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP07_6 |
- ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP11_0 |
- ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP13_2 |
- ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP15_4 |
- ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP17_6;
-
-static inline u32 isif_read(void __iomem *base_addr, u32 offset)
-{
- return readl(base_addr + offset);
-}
-
-static inline void isif_write(void __iomem *base_addr, u32 val, u32 offset)
-{
- writel(val, base_addr + offset);
-}
-
-static inline u32 isif_merge(void __iomem *base_addr, u32 mask, u32 val,
- u32 offset)
-{
- u32 new_val = (isif_read(base_addr, offset) & ~mask) | (val & mask);
-
- isif_write(base_addr, new_val, offset);
-
- return new_val;
-}
-
-static void isif_enable_output_to_sdram(struct vpfe_isif_device *isif, int en)
-{
- isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_WEN_MASK,
- en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
-}
-
-static inline void
-isif_regw_lin_tbl(struct vpfe_isif_device *isif, u32 val, u32 offset, int i)
-{
- if (!i)
- writel(val, isif->isif_cfg.linear_tbl0_addr + offset);
- else
- writel(val, isif->isif_cfg.linear_tbl1_addr + offset);
-}
-
-static void isif_disable_all_modules(struct vpfe_isif_device *isif)
-{
- /* disable BC */
- isif_write(isif->isif_cfg.base_addr, 0, CLAMPCFG);
- /* disable vdfc */
- isif_write(isif->isif_cfg.base_addr, 0, DFCCTL);
- /* disable CSC */
- isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
- /* disable linearization */
- isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
-}
-
-static void isif_enable(struct vpfe_isif_device *isif, int en)
-{
- if (!en)
- /* Before disable isif, disable all ISIF modules */
- isif_disable_all_modules(isif);
-
- /*
- * wait for next VD. Assume lowest scan rate is 12 Hz. So
- * 100 msec delay is good enough
- */
- msleep(100);
- isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_VDHDEN_MASK,
- en, SYNCEN);
-}
-
-/*
- * ISIF helper functions
- */
-
-#define DM365_ISIF_MDFS_OFFSET 15
-#define DM365_ISIF_MDFS_MASK 0x1
-
-/* get field id in isif hardware */
-enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
- u32 field_status;
-
- field_status = isif_read(isif->isif_cfg.base_addr, MODESET);
- return (field_status >> DM365_ISIF_MDFS_OFFSET) &
- DM365_ISIF_MDFS_MASK;
-}
-
-static int
-isif_set_pixel_format(struct vpfe_isif_device *isif, unsigned int pixfmt)
-{
- if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
- if (pixfmt == V4L2_PIX_FMT_SBGGR16)
- isif->isif_cfg.data_pack = ISIF_PACK_16BIT;
- else if ((pixfmt == V4L2_PIX_FMT_SGRBG10DPCM8) ||
- (pixfmt == V4L2_PIX_FMT_SGRBG10ALAW8))
- isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
- else
- return -EINVAL;
-
- isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
- isif->isif_cfg.bayer.v4l2_pix_fmt = pixfmt;
- } else {
- if (pixfmt == V4L2_PIX_FMT_YUYV)
- isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_YCBYCR;
- else if (pixfmt == V4L2_PIX_FMT_UYVY)
- isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
- else
- return -EINVAL;
-
- isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
- isif->isif_cfg.ycbcr.v4l2_pix_fmt = pixfmt;
- }
-
- return 0;
-}
-
-static int
-isif_set_frame_format(struct vpfe_isif_device *isif,
- enum isif_frmfmt frm_fmt)
-{
- if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
- isif->isif_cfg.bayer.frm_fmt = frm_fmt;
- else
- isif->isif_cfg.ycbcr.frm_fmt = frm_fmt;
-
- return 0;
-}
-
-static int isif_set_image_window(struct vpfe_isif_device *isif)
-{
- struct v4l2_rect *win = &isif->crop;
-
- if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
- isif->isif_cfg.bayer.win.top = win->top;
- isif->isif_cfg.bayer.win.left = win->left;
- isif->isif_cfg.bayer.win.width = win->width;
- isif->isif_cfg.bayer.win.height = win->height;
- return 0;
- }
- isif->isif_cfg.ycbcr.win.top = win->top;
- isif->isif_cfg.ycbcr.win.left = win->left;
- isif->isif_cfg.ycbcr.win.width = win->width;
- isif->isif_cfg.ycbcr.win.height = win->height;
-
- return 0;
-}
-
-static int
-isif_set_buftype(struct vpfe_isif_device *isif, enum isif_buftype buf_type)
-{
- if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
- isif->isif_cfg.bayer.buf_type = buf_type;
- else
- isif->isif_cfg.ycbcr.buf_type = buf_type;
-
- return 0;
-}
-
-/* configure format in isif hardware */
-static int
-isif_config_format(struct vpfe_device *vpfe_dev, unsigned int pad)
-{
- struct vpfe_isif_device *vpfe_isif = &vpfe_dev->vpfe_isif;
- enum isif_frmfmt frm_fmt = ISIF_FRMFMT_INTERLACED;
- struct v4l2_pix_format format;
- int ret = 0;
-
- v4l2_fill_pix_format(&format, &vpfe_dev->vpfe_isif.formats[pad]);
- mbus_to_pix(&vpfe_dev->vpfe_isif.formats[pad], &format);
-
- if (isif_set_pixel_format(vpfe_isif, format.pixelformat) < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Failed to set pixel format in isif\n");
- return -EINVAL;
- }
-
- /* call for s_crop will override these values */
- vpfe_isif->crop.left = 0;
- vpfe_isif->crop.top = 0;
- vpfe_isif->crop.width = format.width;
- vpfe_isif->crop.height = format.height;
-
- /* configure the image window */
- isif_set_image_window(vpfe_isif);
-
- switch (vpfe_dev->vpfe_isif.formats[pad].field) {
- case V4L2_FIELD_INTERLACED:
- /* do nothing, since it is default */
- ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_INTERLEAVED);
- break;
-
- case V4L2_FIELD_NONE:
- frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
- /* buffer type only applicable for interlaced scan */
- break;
-
- case V4L2_FIELD_SEQ_TB:
- ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_SEPARATED);
- break;
-
- default:
- return -EINVAL;
- }
-
- /* set the frame format */
- if (!ret)
- ret = isif_set_frame_format(vpfe_isif, frm_fmt);
-
- return ret;
-}
-
-/*
- * isif_try_format() - Try video format on a pad
- * @isif: VPFE isif device
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- */
-static void
-isif_try_format(struct vpfe_isif_device *isif,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- unsigned int width = fmt->format.width;
- unsigned int height = fmt->format.height;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(isif_fmts); i++) {
- if (fmt->format.code == isif_fmts[i])
- break;
- }
-
- /* If not found, use YUYV8_2x8 as default */
- if (i >= ARRAY_SIZE(isif_fmts))
- fmt->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
-
- /* Clamp the size. */
- fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH);
- fmt->format.height = clamp_t(u32, height, 32, MAX_HEIGHT);
-
- /* The data formatter truncates the number of horizontal output
- * pixels to a multiple of 16. To avoid clipping data, allow
- * callers to request an output size bigger than the input size
- * up to the nearest multiple of 16.
- */
- if (fmt->pad == ISIF_PAD_SOURCE)
- fmt->format.width &= ~15;
-}
-
-/*
- * vpfe_isif_buffer_isr() - isif module non-progressive buffer scheduling isr
- * @isif: Pointer to isif subdevice.
- */
-void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
- struct vpfe_video_device *video = &isif->video_out;
- enum v4l2_field field;
- int fid;
-
- if (!video->started)
- return;
-
- field = video->fmt.fmt.pix.field;
-
- if (field == V4L2_FIELD_NONE) {
- /* handle progressive frame capture */
- if (video->cur_frm != video->next_frm)
- vpfe_video_process_buffer_complete(video);
- return;
- }
-
- /* interlaced or TB capture check which field we
- * are in hardware
- */
- fid = vpfe_isif_get_fid(vpfe_dev);
-
- /* switch the software maintained field id */
- video->field_id ^= 1;
- if (fid == video->field_id) {
- /* we are in-sync here,continue */
- if (fid == 0) {
- /*
- * One frame is just being captured. If the
- * next frame is available, release the current
- * frame and move on
- */
- if (video->cur_frm != video->next_frm)
- vpfe_video_process_buffer_complete(video);
- /*
- * based on whether the two fields are stored
- * interleavely or separately in memory,
- * reconfigure the ISIF memory address
- */
- if (field == V4L2_FIELD_SEQ_TB)
- vpfe_video_schedule_bottom_field(video);
- return;
- }
- /*
- * if one field is just being captured configure
- * the next frame get the next frame from the
- * empty queue if no frame is available hold on
- * to the current buffer
- */
- spin_lock(&video->dma_queue_lock);
- if (!list_empty(&video->dma_queue) &&
- video->cur_frm == video->next_frm)
- vpfe_video_schedule_next_buffer(video);
- spin_unlock(&video->dma_queue_lock);
- } else if (fid == 0) {
- /*
- * out of sync. Recover from any hardware out-of-sync.
- * May loose one frame
- */
- video->field_id = fid;
- }
-}
-
-/*
- * vpfe_isif_vidint1_isr() - ISIF module progressive buffer scheduling isr
- * @isif: Pointer to isif subdevice.
- */
-void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif)
-{
- struct vpfe_video_device *video = &isif->video_out;
-
- if (!video->started)
- return;
-
- spin_lock(&video->dma_queue_lock);
- if (video->fmt.fmt.pix.field == V4L2_FIELD_NONE &&
- !list_empty(&video->dma_queue) && video->cur_frm == video->next_frm)
- vpfe_video_schedule_next_buffer(video);
-
- spin_unlock(&video->dma_queue_lock);
-}
-
-/*
- * VPFE video operations
- */
-
-static int isif_video_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
-{
- struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
-
- isif_write(isif->isif_cfg.base_addr, (addr >> 21) &
- ISIF_CADU_BITS, CADU);
- isif_write(isif->isif_cfg.base_addr, (addr >> 5) &
- ISIF_CADL_BITS, CADL);
-
- return 0;
-}
-
-static const struct vpfe_video_operations isif_video_ops = {
- .queue = isif_video_queue,
-};
-
-/*
- * V4L2 subdev operations
- */
-
-/* Parameter operations */
-static int isif_get_params(struct v4l2_subdev *sd, void *params)
-{
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
-
- /* only raw module parameters can be set through the IOCTL */
- if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
- return -EINVAL;
- memcpy(params, &isif->isif_cfg.bayer.config_params,
- sizeof(isif->isif_cfg.bayer.config_params));
- return 0;
-}
-
-static int isif_validate_df_csc_params(const struct vpfe_isif_df_csc *df_csc)
-{
- const struct vpfe_isif_color_space_conv *csc;
- int err = -EINVAL;
- int i;
-
- if (!df_csc->df_or_csc) {
- /* csc configuration */
- csc = &df_csc->csc;
- if (csc->en) {
- for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++)
- if (csc->coeff[i].integer >
- ISIF_CSC_COEF_INTEG_MASK ||
- csc->coeff[i].decimal >
- ISIF_CSC_COEF_DECIMAL_MASK) {
- pr_err("Invalid CSC coefficients\n");
- return err;
- }
- }
- }
- if (df_csc->start_pix > ISIF_DF_CSC_SPH_MASK) {
- pr_err("Invalid df_csc start pix value\n");
- return err;
- }
-
- if (df_csc->num_pixels > ISIF_DF_NUMPIX) {
- pr_err("Invalid df_csc num pixels value\n");
- return err;
- }
-
- if (df_csc->start_line > ISIF_DF_CSC_LNH_MASK) {
- pr_err("Invalid df_csc start_line value\n");
- return err;
- }
-
- if (df_csc->num_lines > ISIF_DF_NUMLINES) {
- pr_err("Invalid df_csc num_lines value\n");
- return err;
- }
-
- return 0;
-}
-
-#define DM365_ISIF_MAX_VDFLSFT 4
-#define DM365_ISIF_MAX_VDFSLV 4095
-#define DM365_ISIF_MAX_DFCMEM0 0x1fff
-#define DM365_ISIF_MAX_DFCMEM1 0x1fff
-
-static int isif_validate_dfc_params(const struct vpfe_isif_dfc *dfc)
-{
- int err = -EINVAL;
- int i;
-
- if (!dfc->en)
- return 0;
-
- if (dfc->corr_whole_line > 1) {
- pr_err("Invalid corr_whole_line value\n");
- return err;
- }
-
- if (dfc->def_level_shift > DM365_ISIF_MAX_VDFLSFT) {
- pr_err("Invalid def_level_shift value\n");
- return err;
- }
-
- if (dfc->def_sat_level > DM365_ISIF_MAX_VDFSLV) {
- pr_err("Invalid def_sat_level value\n");
- return err;
- }
-
- if (!dfc->num_vdefects ||
- dfc->num_vdefects > VPFE_ISIF_VDFC_TABLE_SIZE) {
- pr_err("Invalid num_vdefects value\n");
- return err;
- }
-
- for (i = 0; i < VPFE_ISIF_VDFC_TABLE_SIZE; i++) {
- if (dfc->table[i].pos_vert > DM365_ISIF_MAX_DFCMEM0) {
- pr_err("Invalid pos_vert value\n");
- return err;
- }
- if (dfc->table[i].pos_horz > DM365_ISIF_MAX_DFCMEM1) {
- pr_err("Invalid pos_horz value\n");
- return err;
- }
- }
-
- return 0;
-}
-
-#define DM365_ISIF_MAX_CLVRV 0xfff
-#define DM365_ISIF_MAX_CLDC 0x1fff
-#define DM365_ISIF_MAX_CLHSH 0x1fff
-#define DM365_ISIF_MAX_CLHSV 0x1fff
-#define DM365_ISIF_MAX_CLVSH 0x1fff
-#define DM365_ISIF_MAX_CLVSV 0x1fff
-#define DM365_ISIF_MAX_HEIGHT_BLACK_REGION 0x1fff
-
-static int isif_validate_bclamp_params(const struct vpfe_isif_black_clamp *bclamp)
-{
- int err = -EINVAL;
-
- if (bclamp->dc_offset > DM365_ISIF_MAX_CLDC) {
- pr_err("Invalid bclamp dc_offset value\n");
- return err;
- }
- if (!bclamp->en)
- return 0;
- if (bclamp->horz.clamp_pix_limit > 1) {
- pr_err("Invalid bclamp horz clamp_pix_limit value\n");
- return err;
- }
- if (bclamp->horz.win_count_calc < 1 ||
- bclamp->horz.win_count_calc > 32) {
- pr_err("Invalid bclamp horz win_count_calc value\n");
- return err;
- }
- if (bclamp->horz.win_start_h_calc > DM365_ISIF_MAX_CLHSH) {
- pr_err("Invalid bclamp win_start_v_calc value\n");
- return err;
- }
-
- if (bclamp->horz.win_start_v_calc > DM365_ISIF_MAX_CLHSV) {
- pr_err("Invalid bclamp win_start_v_calc value\n");
- return err;
- }
- if (bclamp->vert.reset_clamp_val > DM365_ISIF_MAX_CLVRV) {
- pr_err("Invalid bclamp reset_clamp_val value\n");
- return err;
- }
- if (bclamp->vert.ob_v_sz_calc > DM365_ISIF_MAX_HEIGHT_BLACK_REGION) {
- pr_err("Invalid bclamp ob_v_sz_calc value\n");
- return err;
- }
- if (bclamp->vert.ob_start_h > DM365_ISIF_MAX_CLVSH) {
- pr_err("Invalid bclamp ob_start_h value\n");
- return err;
- }
- if (bclamp->vert.ob_start_v > DM365_ISIF_MAX_CLVSV) {
- pr_err("Invalid bclamp ob_start_h value\n");
- return err;
- }
- return 0;
-}
-
-static int
-isif_validate_raw_params(const struct vpfe_isif_raw_config *params)
-{
- int ret;
-
- ret = isif_validate_df_csc_params(&params->df_csc);
- if (ret)
- return ret;
- ret = isif_validate_dfc_params(&params->dfc);
- if (ret)
- return ret;
- return isif_validate_bclamp_params(&params->bclamp);
-}
-
-static int isif_set_params(struct v4l2_subdev *sd, const struct vpfe_isif_raw_config *params)
-{
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
- int ret = -EINVAL;
-
- /* only raw module parameters can be set through the IOCTL */
- if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
- return ret;
-
- if (!isif_validate_raw_params(params)) {
- memcpy(&isif->isif_cfg.bayer.config_params, params,
- sizeof(*params));
- ret = 0;
- }
- return ret;
-}
-/*
- * isif_ioctl() - isif module private ioctl's
- * @sd: VPFE isif V4L2 subdevice
- * @cmd: ioctl command
- * @arg: ioctl argument
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static long isif_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case VIDIOC_VPFE_ISIF_S_RAW_PARAMS:
- return isif_set_params(sd, arg);
-
- case VIDIOC_VPFE_ISIF_G_RAW_PARAMS:
- return isif_get_params(sd, arg);
-
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-static void isif_config_gain_offset(struct vpfe_isif_device *isif)
-{
- struct vpfe_isif_gain_offsets_adj *gain_off_ptr =
- &isif->isif_cfg.bayer.config_params.gain_offset;
- void __iomem *base = isif->isif_cfg.base_addr;
- u32 val;
-
- val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) |
- ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) |
- ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) |
- ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) |
- ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) |
- ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT);
- isif_merge(base, GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
-
- isif_write(base, isif->isif_cfg.isif_gain_params.cr_gain, CRGAIN);
- isif_write(base, isif->isif_cfg.isif_gain_params.cgr_gain, CGRGAIN);
- isif_write(base, isif->isif_cfg.isif_gain_params.cgb_gain, CGBGAIN);
- isif_write(base, isif->isif_cfg.isif_gain_params.cb_gain, CBGAIN);
- isif_write(base, isif->isif_cfg.isif_gain_params.offset & OFFSET_MASK,
- COFSTA);
-
-}
-
-static void isif_config_bclamp(struct vpfe_isif_device *isif,
- struct vpfe_isif_black_clamp *bc)
-{
- u32 val;
-
- /**
- * DC Offset is always added to image data irrespective of bc enable
- * status
- */
- val = bc->dc_offset & ISIF_BC_DCOFFSET_MASK;
- isif_write(isif->isif_cfg.base_addr, val, CLDCOFST);
-
- if (!bc->en)
- return;
-
- val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) <<
- ISIF_BC_MODE_COLOR_SHIFT;
-
- /* Enable BC and horizontal clamp calculation parameters */
- val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) <<
- ISIF_HORZ_BC_MODE_SHIFT);
-
- isif_write(isif->isif_cfg.base_addr, val, CLAMPCFG);
-
- if (bc->horz.mode != VPFE_ISIF_HORZ_BC_DISABLE) {
- /*
- * Window count for calculation
- * Base window selection
- * pixel limit
- * Horizontal size of window
- * vertical size of the window
- * Horizontal start position of the window
- * Vertical start position of the window
- */
- val = (bc->horz.win_count_calc & ISIF_HORZ_BC_WIN_COUNT_MASK) |
- ((bc->horz.base_win_sel_calc & 1) <<
- ISIF_HORZ_BC_WIN_SEL_SHIFT) |
- ((bc->horz.clamp_pix_limit & 1) <<
- ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
- ((bc->horz.win_h_sz_calc &
- ISIF_HORZ_BC_WIN_H_SIZE_MASK) <<
- ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
- ((bc->horz.win_v_sz_calc &
- ISIF_HORZ_BC_WIN_V_SIZE_MASK) <<
- ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
-
- isif_write(isif->isif_cfg.base_addr, val, CLHWIN0);
-
- val = bc->horz.win_start_h_calc & ISIF_HORZ_BC_WIN_START_H_MASK;
- isif_write(isif->isif_cfg.base_addr, val, CLHWIN1);
-
- val = bc->horz.win_start_v_calc & ISIF_HORZ_BC_WIN_START_V_MASK;
- isif_write(isif->isif_cfg.base_addr, val, CLHWIN2);
- }
-
- /* vertical clamp calculation parameters */
- /* OB H Valid */
- val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK;
-
- /* Reset clamp value sel for previous line */
- val |= (bc->vert.reset_val_sel & ISIF_VERT_BC_RST_VAL_SEL_MASK) <<
- ISIF_VERT_BC_RST_VAL_SEL_SHIFT;
-
- /* Line average coefficient */
- val |= bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT;
- isif_write(isif->isif_cfg.base_addr, val, CLVWIN0);
-
- /* Configured reset value */
- if (bc->vert.reset_val_sel == VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL) {
- val = bc->vert.reset_clamp_val & ISIF_VERT_BC_RST_VAL_MASK;
- isif_write(isif->isif_cfg.base_addr, val, CLVRV);
- }
-
- /* Optical Black horizontal start position */
- val = bc->vert.ob_start_h & ISIF_VERT_BC_OB_START_HORZ_MASK;
- isif_write(isif->isif_cfg.base_addr, val, CLVWIN1);
-
- /* Optical Black vertical start position */
- val = bc->vert.ob_start_v & ISIF_VERT_BC_OB_START_VERT_MASK;
- isif_write(isif->isif_cfg.base_addr, val, CLVWIN2);
-
- val = bc->vert.ob_v_sz_calc & ISIF_VERT_BC_OB_VERT_SZ_MASK;
- isif_write(isif->isif_cfg.base_addr, val, CLVWIN3);
-
- /* Vertical start position for BC subtraction */
- val = bc->vert_start_sub & ISIF_BC_VERT_START_SUB_V_MASK;
- isif_write(isif->isif_cfg.base_addr, val, CLSV);
-}
-
-/* This function will configure the window size to be capture in ISIF reg */
-static void
-isif_setwin(struct vpfe_isif_device *isif, struct v4l2_rect *image_win,
- enum isif_frmfmt frm_fmt, int ppc, int mode)
-{
- int horz_nr_pixels;
- int vert_nr_lines;
- int horz_start;
- int vert_start;
- int mid_img;
-
- /*
- * ppc - per pixel count. indicates how many pixels per cell
- * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
- * raw capture this is 1
- */
- horz_start = image_win->left << (ppc - 1);
- horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
-
- /* Writing the horizontal info into the registers */
- isif_write(isif->isif_cfg.base_addr,
- horz_start & START_PX_HOR_MASK, SPH);
- isif_write(isif->isif_cfg.base_addr,
- horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
- vert_start = image_win->top;
-
- if (frm_fmt == ISIF_FRMFMT_INTERLACED) {
- vert_nr_lines = (image_win->height >> 1) - 1;
- vert_start >>= 1;
- /* To account for VD since line 0 doesn't have any data */
- vert_start += 1;
- } else {
- /* To account for VD since line 0 doesn't have any data */
- vert_start += 1;
- vert_nr_lines = image_win->height - 1;
- /* configure VDINT0 and VDINT1 */
- mid_img = vert_start + (image_win->height / 2);
- isif_write(isif->isif_cfg.base_addr, mid_img, VDINT1);
- }
-
- if (!mode)
- isif_write(isif->isif_cfg.base_addr, 0, VDINT0);
- else
- isif_write(isif->isif_cfg.base_addr, vert_nr_lines, VDINT0);
- isif_write(isif->isif_cfg.base_addr,
- vert_start & START_VER_ONE_MASK, SLV0);
- isif_write(isif->isif_cfg.base_addr,
- vert_start & START_VER_TWO_MASK, SLV1);
- isif_write(isif->isif_cfg.base_addr,
- vert_nr_lines & NUM_LINES_VER, LNV);
-}
-
-#define DM365_ISIF_DFCMWR_MEMORY_WRITE 1
-#define DM365_ISIF_DFCMRD_MEMORY_READ 0x2
-
-static void
-isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
-{
-#define DFC_WRITE_WAIT_COUNT 1000
- u32 count = DFC_WRITE_WAIT_COUNT;
- u32 val;
- int i;
-
- if (!vdfc->en)
- return;
-
- /* Correction mode */
- val = (vdfc->corr_mode & ISIF_VDFC_CORR_MOD_MASK) <<
- ISIF_VDFC_CORR_MOD_SHIFT;
-
- /* Correct whole line or partial */
- if (vdfc->corr_whole_line)
- val |= BIT(ISIF_VDFC_CORR_WHOLE_LN_SHIFT);
-
- /* level shift value */
- val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) <<
- ISIF_VDFC_LEVEL_SHFT_SHIFT;
-
- isif_write(isif->isif_cfg.base_addr, val, DFCCTL);
-
- /* Defect saturation level */
- val = vdfc->def_sat_level & ISIF_VDFC_SAT_LEVEL_MASK;
- isif_write(isif->isif_cfg.base_addr, val, VDFSATLV);
-
- isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_vert &
- ISIF_VDFC_POS_MASK, DFCMEM0);
- isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_horz &
- ISIF_VDFC_POS_MASK, DFCMEM1);
- if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
- vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
- isif_write(isif->isif_cfg.base_addr,
- vdfc->table[0].level_at_pos, DFCMEM2);
- isif_write(isif->isif_cfg.base_addr,
- vdfc->table[0].level_up_pixels, DFCMEM3);
- isif_write(isif->isif_cfg.base_addr,
- vdfc->table[0].level_low_pixels, DFCMEM4);
- }
-
- val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
- /* set DFCMARST and set DFCMWR */
- val |= BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
- val |= 1;
- isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
-
- while (count && (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x01))
- count--;
-
- val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
- if (!count) {
- pr_debug("defect table write timeout !!\n");
- return;
- }
-
- for (i = 1; i < vdfc->num_vdefects; i++) {
- isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_vert &
- ISIF_VDFC_POS_MASK, DFCMEM0);
-
- isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_horz &
- ISIF_VDFC_POS_MASK, DFCMEM1);
-
- if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
- vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
- isif_write(isif->isif_cfg.base_addr,
- vdfc->table[i].level_at_pos, DFCMEM2);
- isif_write(isif->isif_cfg.base_addr,
- vdfc->table[i].level_up_pixels, DFCMEM3);
- isif_write(isif->isif_cfg.base_addr,
- vdfc->table[i].level_low_pixels, DFCMEM4);
- }
- val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
- /* clear DFCMARST and set DFCMWR */
- val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
- val |= 1;
- isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
-
- count = DFC_WRITE_WAIT_COUNT;
- while (count && (isif_read(isif->isif_cfg.base_addr,
- DFCMEMCTL) & 0x01))
- count--;
-
- val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
- if (!count) {
- pr_debug("defect table write timeout !!\n");
- return;
- }
- }
- if (vdfc->num_vdefects < VPFE_ISIF_VDFC_TABLE_SIZE) {
- /* Extra cycle needed */
- isif_write(isif->isif_cfg.base_addr, 0, DFCMEM0);
- isif_write(isif->isif_cfg.base_addr,
- DM365_ISIF_MAX_DFCMEM1, DFCMEM1);
- isif_write(isif->isif_cfg.base_addr,
- DM365_ISIF_DFCMWR_MEMORY_WRITE, DFCMEMCTL);
- }
- /* enable VDFC */
- isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
- (1 << ISIF_VDFC_EN_SHIFT), DFCCTL);
-
- isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
- (0 << ISIF_VDFC_EN_SHIFT), DFCCTL);
-
- isif_write(isif->isif_cfg.base_addr, 0x6, DFCMEMCTL);
- for (i = 0; i < vdfc->num_vdefects; i++) {
- count = DFC_WRITE_WAIT_COUNT;
- while (count &&
- (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x2))
- count--;
- val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
- if (!count) {
- pr_debug("defect table write timeout !!\n");
- return;
- }
- isif_write(isif->isif_cfg.base_addr,
- DM365_ISIF_DFCMRD_MEMORY_READ, DFCMEMCTL);
- }
-}
-
-static void
-isif_config_csc(struct vpfe_isif_device *isif, struct vpfe_isif_df_csc *df_csc)
-{
- u32 val1;
- u32 val2;
- u32 i;
-
- if (!df_csc->csc.en) {
- isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
- return;
- }
- /* initialize all bits to 0 */
- val1 = 0;
- for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) {
- if ((i % 2) == 0) {
- /* CSCM - LSB */
- val1 = ((df_csc->csc.coeff[i].integer &
- ISIF_CSC_COEF_INTEG_MASK) <<
- ISIF_CSC_COEF_INTEG_SHIFT) |
- ((df_csc->csc.coeff[i].decimal &
- ISIF_CSC_COEF_DECIMAL_MASK));
- } else {
-
- /* CSCM - MSB */
- val2 = ((df_csc->csc.coeff[i].integer &
- ISIF_CSC_COEF_INTEG_MASK) <<
- ISIF_CSC_COEF_INTEG_SHIFT) |
- ((df_csc->csc.coeff[i].decimal &
- ISIF_CSC_COEF_DECIMAL_MASK));
- val2 <<= ISIF_CSCM_MSB_SHIFT;
- val2 |= val1;
- isif_write(isif->isif_cfg.base_addr, val2,
- (CSCM0 + ((i-1) << 1)));
- }
- }
- /* program the active area */
- isif_write(isif->isif_cfg.base_addr, df_csc->start_pix &
- ISIF_DF_CSC_SPH_MASK, FMTSPH);
- /*
- * one extra pixel as required for CSC. Actually number of
- * pixel - 1 should be configured in this register. So we
- * need to subtract 1 before writing to FMTSPH, but we will
- * not do this since csc requires one extra pixel
- */
- isif_write(isif->isif_cfg.base_addr, df_csc->num_pixels &
- ISIF_DF_CSC_SPH_MASK, FMTLNH);
- isif_write(isif->isif_cfg.base_addr, df_csc->start_line &
- ISIF_DF_CSC_SPH_MASK, FMTSLV);
- /*
- * one extra line as required for CSC. See reason documented for
- * num_pixels
- */
- isif_write(isif->isif_cfg.base_addr, df_csc->num_lines &
- ISIF_DF_CSC_SPH_MASK, FMTLNV);
- /* Enable CSC */
- isif_write(isif->isif_cfg.base_addr, 1, CSCCTL);
-}
-
-static void
-isif_config_linearization(struct vpfe_isif_device *isif,
- struct vpfe_isif_linearize *linearize)
-{
- u32 val;
- u32 i;
-
- if (!linearize->en) {
- isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
- return;
- }
- /* shift value for correction */
- val = (linearize->corr_shft & ISIF_LIN_CORRSFT_MASK) <<
- ISIF_LIN_CORRSFT_SHIFT;
- /* enable */
- val |= 1;
- isif_write(isif->isif_cfg.base_addr, val, LINCFG0);
- /* Scale factor */
- val = (linearize->scale_fact.integer & 1) <<
- ISIF_LIN_SCALE_FACT_INTEG_SHIFT;
- val |= linearize->scale_fact.decimal & ISIF_LIN_SCALE_FACT_DECIMAL_MASK;
- isif_write(isif->isif_cfg.base_addr, val, LINCFG1);
-
- for (i = 0; i < VPFE_ISIF_LINEAR_TAB_SIZE; i++) {
- val = linearize->table[i] & ISIF_LIN_ENTRY_MASK;
- if (i%2)
- isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 1);
- else
- isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 0);
- }
-}
-
-static void
-isif_config_culling(struct vpfe_isif_device *isif, struct vpfe_isif_cul *cul)
-{
- u32 val;
-
- /* Horizontal pattern */
- val = cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT;
- val |= cul->hcpat_odd;
- isif_write(isif->isif_cfg.base_addr, val, CULH);
- /* vertical pattern */
- isif_write(isif->isif_cfg.base_addr, cul->vcpat, CULV);
- /* LPF */
- isif_merge(isif->isif_cfg.base_addr, ISIF_LPF_MASK << ISIF_LPF_SHIFT,
- cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
-}
-
-static int isif_get_pix_fmt(u32 mbus_code)
-{
- switch (mbus_code) {
- case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
- case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
- case MEDIA_BUS_FMT_SGRBG12_1X12:
- return ISIF_PIXFMT_RAW;
-
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_YUYV10_2X10:
- case MEDIA_BUS_FMT_Y8_1X8:
- return ISIF_PIXFMT_YCBCR_8BIT;
-
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YUYV10_1X20:
- return ISIF_PIXFMT_YCBCR_16BIT;
-
- default:
- break;
- }
- return -EINVAL;
-}
-
-#define ISIF_INTERLACE_INVERSE_MODE 0x4b6d
-#define ISIF_INTERLACE_NON_INVERSE_MODE 0x0b6d
-#define ISIF_PROGRESSIVE_INVERSE_MODE 0x4000
-#define ISIF_PROGRESSIVE_NON_INVERSE_MODE 0x0000
-
-static int isif_config_raw(struct v4l2_subdev *sd, int mode)
-{
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
- struct isif_params_raw *params = &isif->isif_cfg.bayer;
- struct vpfe_isif_raw_config *module_params =
- &isif->isif_cfg.bayer.config_params;
- struct v4l2_mbus_framefmt *format;
- int pix_fmt;
- u32 val;
-
- format = &isif->formats[ISIF_PAD_SINK];
-
- /* In case of user has set BT656IF earlier, it should be reset
- * when configuring for raw input.
- */
- isif_write(isif->isif_cfg.base_addr, 0, REC656IF);
- /* Configure CCDCFG register
- * Set CCD Not to swap input since input is RAW data
- * Set FID detection function to Latch at V-Sync
- * Set WENLOG - isif valid area
- * Set TRGSEL
- * Set EXTRG
- * Packed to 8 or 16 bits
- */
- val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
- ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
- ISIF_CCDCFG_EXTRG_DISABLE | (isif->isif_cfg.data_pack &
- ISIF_DATA_PACK_MASK);
- isif_write(isif->isif_cfg.base_addr, val, CCDCFG);
-
- pix_fmt = isif_get_pix_fmt(format->code);
- if (pix_fmt < 0) {
- pr_debug("Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- /*
- * Configure the vertical sync polarity(MODESET.VDPOL)
- * Configure the horizontal sync polarity (MODESET.HDPOL)
- * Configure frame id polarity (MODESET.FLDPOL)
- * Configure data polarity
- * Configure External WEN Selection
- * Configure frame format(progressive or interlace)
- * Configure pixel format (Input mode)
- * Configure the data shift
- */
- val = ISIF_VDHDOUT_INPUT | ((params->vd_pol & ISIF_VD_POL_MASK) <<
- ISIF_VD_POL_SHIFT) | ((params->hd_pol & ISIF_HD_POL_MASK) <<
- ISIF_HD_POL_SHIFT) | ((params->fid_pol & ISIF_FID_POL_MASK) <<
- ISIF_FID_POL_SHIFT) | ((ISIF_DATAPOL_NORMAL &
- ISIF_DATAPOL_MASK) << ISIF_DATAPOL_SHIFT) | ((ISIF_EXWEN_DISABLE &
- ISIF_EXWEN_MASK) << ISIF_EXWEN_SHIFT) | ((params->frm_fmt &
- ISIF_FRM_FMT_MASK) << ISIF_FRM_FMT_SHIFT) | ((pix_fmt &
- ISIF_INPUT_MASK) << ISIF_INPUT_SHIFT);
-
- /* currently only MEDIA_BUS_FMT_SGRBG12_1X12 is
- * supported. shift appropriately depending on
- * different MBUS fmt's added
- */
- if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
- val |= ((VPFE_ISIF_NO_SHIFT &
- ISIF_DATASFT_MASK) << ISIF_DATASFT_SHIFT);
-
- isif_write(isif->isif_cfg.base_addr, val, MODESET);
- /*
- * Configure GAMMAWD register
- * CFA pattern setting
- */
- val = (params->cfa_pat & ISIF_GAMMAWD_CFA_MASK) <<
- ISIF_GAMMAWD_CFA_SHIFT;
- /* Gamma msb */
- if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10ALAW8)
- val = val | ISIF_ALAW_ENABLE;
-
- val = val | ((params->data_msb & ISIF_ALAW_GAMA_WD_MASK) <<
- ISIF_ALAW_GAMA_WD_SHIFT);
-
- isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD);
- /* Configure DPCM compression settings */
- if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) {
- val = BIT(ISIF_DPCM_EN_SHIFT);
- val |= (params->dpcm_predictor &
- ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT;
- }
- isif_write(isif->isif_cfg.base_addr, val, MISC);
- /* Configure Gain & Offset */
- isif_config_gain_offset(isif);
- /* Configure Color pattern */
- if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
- val = isif_sgrbg_pattern;
- else
- /* default set to rggb */
- val = isif_srggb_pattern;
-
- isif_write(isif->isif_cfg.base_addr, val, CCOLP);
-
- /* Configure HSIZE register */
- val = (params->horz_flip_en & ISIF_HSIZE_FLIP_MASK) <<
- ISIF_HSIZE_FLIP_SHIFT;
-
- /* calculate line offset in 32 bytes based on pack value */
- if (isif->isif_cfg.data_pack == ISIF_PACK_8BIT)
- val |= ((params->win.width + 31) >> 5) & ISIF_LINEOFST_MASK;
- else if (isif->isif_cfg.data_pack == ISIF_PACK_12BIT)
- val |= ((((params->win.width + (params->win.width >> 2)) +
- 31) >> 5) & ISIF_LINEOFST_MASK);
- else
- val |= (((params->win.width * 2) + 31) >> 5) &
- ISIF_LINEOFST_MASK;
- isif_write(isif->isif_cfg.base_addr, val, HSIZE);
- /* Configure SDOFST register */
- if (params->frm_fmt == ISIF_FRMFMT_INTERLACED) {
- if (params->image_invert_en)
- /* For interlace inverse mode */
- isif_write(isif->isif_cfg.base_addr,
- ISIF_INTERLACE_INVERSE_MODE, SDOFST);
- else
- /* For interlace non inverse mode */
- isif_write(isif->isif_cfg.base_addr,
- ISIF_INTERLACE_NON_INVERSE_MODE, SDOFST);
- } else if (params->frm_fmt == ISIF_FRMFMT_PROGRESSIVE) {
- if (params->image_invert_en)
- isif_write(isif->isif_cfg.base_addr,
- ISIF_PROGRESSIVE_INVERSE_MODE, SDOFST);
- else
- /* For progessive non inverse mode */
- isif_write(isif->isif_cfg.base_addr,
- ISIF_PROGRESSIVE_NON_INVERSE_MODE, SDOFST);
- }
- /* Configure video window */
- isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
- /* Configure Black Clamp */
- isif_config_bclamp(isif, &module_params->bclamp);
- /* Configure Vertical Defection Pixel Correction */
- isif_config_dfc(isif, &module_params->dfc);
- if (!module_params->df_csc.df_or_csc)
- /* Configure Color Space Conversion */
- isif_config_csc(isif, &module_params->df_csc);
-
- isif_config_linearization(isif, &module_params->linearize);
- /* Configure Culling */
- isif_config_culling(isif, &module_params->culling);
- /* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */
- val = module_params->horz_offset & ISIF_DATA_H_OFFSET_MASK;
- isif_write(isif->isif_cfg.base_addr, val, DATAHOFST);
-
- val = module_params->vert_offset & ISIF_DATA_V_OFFSET_MASK;
- isif_write(isif->isif_cfg.base_addr, val, DATAVOFST);
-
- return 0;
-}
-
-#define DM365_ISIF_HSIZE_MASK 0xffffffe0
-#define DM365_ISIF_SDOFST_2_LINES 0x00000249
-
-/* This function will configure ISIF for YCbCr parameters. */
-static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
-{
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
- struct isif_ycbcr_config *params = &isif->isif_cfg.ycbcr;
- struct v4l2_mbus_framefmt *format;
- int pix_fmt;
- u32 modeset;
- u32 ccdcfg;
-
- format = &isif->formats[ISIF_PAD_SINK];
- /*
- * first reset the ISIF
- * all registers have default values after reset
- * This is important since we assume default values to be set in
- * a lot of registers that we didn't touch
- */
- /* start with all bits zero */
- ccdcfg = 0;
- modeset = 0;
- pix_fmt = isif_get_pix_fmt(format->code);
- if (pix_fmt < 0) {
- pr_debug("Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- /* configure pixel format or input mode */
- modeset = modeset | ((pix_fmt & ISIF_INPUT_MASK) <<
- ISIF_INPUT_SHIFT) | ((params->frm_fmt & ISIF_FRM_FMT_MASK) <<
- ISIF_FRM_FMT_SHIFT) | (((params->fid_pol &
- ISIF_FID_POL_MASK) << ISIF_FID_POL_SHIFT)) |
- (((params->hd_pol & ISIF_HD_POL_MASK) << ISIF_HD_POL_SHIFT)) |
- (((params->vd_pol & ISIF_VD_POL_MASK) << ISIF_VD_POL_SHIFT));
- /* pack the data to 8-bit CCDCCFG */
- switch (format->code) {
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
- pr_debug("Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- modeset |= ((VPFE_PINPOL_NEGATIVE & ISIF_VD_POL_MASK) <<
- ISIF_VD_POL_SHIFT);
- isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
- ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR;
- break;
-
- case MEDIA_BUS_FMT_YUYV10_2X10:
- if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
- pr_debug("Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- /* setup BT.656, embedded sync */
- isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
- /* enable 10 bit mode in ccdcfg */
- ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR |
- ISIF_BW656_ENABLE;
- break;
-
- case MEDIA_BUS_FMT_YUYV10_1X20:
- if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
- pr_debug("Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
- break;
-
- case MEDIA_BUS_FMT_Y8_1X8:
- ccdcfg |= ISIF_PACK_8BIT;
- ccdcfg |= ISIF_YCINSWP_YCBCR;
- if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
- pr_debug("Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- break;
-
- case MEDIA_BUS_FMT_YUYV8_1X16:
- if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
- pr_debug("Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- break;
-
- default:
- /* should never come here */
- pr_debug("Invalid interface type\n");
- return -EINVAL;
- }
- isif_write(isif->isif_cfg.base_addr, modeset, MODESET);
- /* Set up pix order */
- ccdcfg |= (params->pix_order & ISIF_PIX_ORDER_MASK) <<
- ISIF_PIX_ORDER_SHIFT;
- isif_write(isif->isif_cfg.base_addr, ccdcfg, CCDCFG);
- /* configure video window */
- if (format->code == MEDIA_BUS_FMT_YUYV10_1X20 ||
- format->code == MEDIA_BUS_FMT_YUYV8_1X16)
- isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
- else
- isif_setwin(isif, &params->win, params->frm_fmt, 2, mode);
-
- /*
- * configure the horizontal line offset
- * this is done by rounding up width to a multiple of 16 pixels
- * and multiply by two to account for y:cb:cr 4:2:2 data
- */
- isif_write(isif->isif_cfg.base_addr,
- ((((params->win.width * 2) + 31) &
- DM365_ISIF_HSIZE_MASK) >> 5), HSIZE);
-
- /* configure the memory line offset */
- if (params->frm_fmt == ISIF_FRMFMT_INTERLACED &&
- params->buf_type == ISIF_BUFTYPE_FLD_INTERLEAVED)
- /* two fields are interleaved in memory */
- isif_write(isif->isif_cfg.base_addr,
- DM365_ISIF_SDOFST_2_LINES, SDOFST);
- return 0;
-}
-
-static int isif_configure(struct v4l2_subdev *sd, int mode)
-{
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = &isif->formats[ISIF_PAD_SINK];
-
- switch (format->code) {
- case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
- case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
- case MEDIA_BUS_FMT_SGRBG12_1X12:
- return isif_config_raw(sd, mode);
-
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_YUYV10_2X10:
- case MEDIA_BUS_FMT_Y8_1X8:
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YUYV10_1X20:
- return isif_config_ycbcr(sd, mode);
-
- default:
- break;
- }
- return -EINVAL;
-}
-
-/*
- * isif_set_stream() - Enable/Disable streaming on the ISIF module
- * @sd: VPFE ISIF V4L2 subdevice
- * @enable: Enable/disable stream
- */
-static int isif_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
- int ret;
-
- if (enable) {
- ret = isif_configure(sd,
- (isif->output == ISIF_OUTPUT_MEMORY) ? 0 : 1);
- if (ret)
- return ret;
- if (isif->output == ISIF_OUTPUT_MEMORY)
- isif_enable_output_to_sdram(isif, 1);
- isif_enable(isif, 1);
- } else {
- isif_enable(isif, 0);
- isif_enable_output_to_sdram(isif, 0);
- }
-
- return 0;
-}
-
-/*
- * __isif_get_format() - helper function for getting isif format
- * @isif: pointer to isif private structure.
- * @pad: pad number.
- * @cfg: V4L2 subdev pad config
- * @which: wanted subdev format.
- */
-static struct v4l2_mbus_framefmt *
-__isif_get_format(struct vpfe_isif_device *isif,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&isif->subdev, cfg, pad);
-
- return &isif->formats[pad];
-}
-
-/*
- * isif_set_format() - set format on pad
- * @sd : VPFE ISIF device
- * @cfg : V4L2 subdev pad config
- * @fmt : pointer to v4l2 subdev format structure
- *
- * Return 0 on success or -EINVAL if format or pad is invalid
- */
-static int
-isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
- struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
- struct v4l2_mbus_framefmt *format;
-
- format = __isif_get_format(isif, cfg, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- isif_try_format(isif, cfg, fmt);
- memcpy(format, &fmt->format, sizeof(*format));
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- return 0;
-
- if (fmt->pad == ISIF_PAD_SOURCE)
- return isif_config_format(vpfe_dev, fmt->pad);
-
- return 0;
-}
-
-/*
- * isif_get_format() - Retrieve the video format on a pad
- * @sd: VPFE ISIF V4L2 subdevice
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- *
- * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
- * to the format type.
- */
-static int
-isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __isif_get_format(vpfe_isif, cfg, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- memcpy(&fmt->format, format, sizeof(fmt->format));
-
- return 0;
-}
-
-/*
- * isif_enum_frame_size() - enum frame sizes on pads
- * @sd: VPFE isif V4L2 subdevice
- * @cfg: V4L2 subdev pad config
- * @code: pointer to v4l2_subdev_frame_size_enum structure
- */
-static int
-isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
- struct v4l2_subdev_format format;
-
- if (fse->index != 0)
- return -EINVAL;
-
- format.pad = fse->pad;
- format.format.code = fse->code;
- format.format.width = 1;
- format.format.height = 1;
- format.which = fse->which;
- isif_try_format(isif, cfg, &format);
- fse->min_width = format.format.width;
- fse->min_height = format.format.height;
-
- if (format.format.code != fse->code)
- return -EINVAL;
-
- format.pad = fse->pad;
- format.format.code = fse->code;
- format.format.width = -1;
- format.format.height = -1;
- format.which = fse->which;
- isif_try_format(isif, cfg, &format);
- fse->max_width = format.format.width;
- fse->max_height = format.format.height;
-
- return 0;
-}
-
-/*
- * isif_enum_mbus_code() - enum mbus codes for pads
- * @sd: VPFE isif V4L2 subdevice
- * @cfg: V4L2 subdev pad config
- * @code: pointer to v4l2_subdev_mbus_code_enum structure
- */
-static int
-isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- switch (code->pad) {
- case ISIF_PAD_SINK:
- case ISIF_PAD_SOURCE:
- if (code->index >= ARRAY_SIZE(isif_fmts))
- return -EINVAL;
- code->code = isif_fmts[code->index];
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * isif_pad_set_selection() - set crop rectangle on pad
- * @sd: VPFE isif V4L2 subdevice
- * @cfg: V4L2 subdev pad config
- * @code: pointer to v4l2_subdev_mbus_code_enum structure
- *
- * Return 0 on success, -EINVAL if pad is invalid
- */
-static int
-isif_pad_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_selection *sel)
-{
- struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- /* check whether it's a valid pad and target */
- if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- format = __isif_get_format(vpfe_isif, cfg, sel->pad, sel->which);
- if (format == NULL)
- return -EINVAL;
-
- /* check wether crop rect is within limits */
- if (sel->r.top < 0 || sel->r.left < 0 ||
- (sel->r.left + sel->r.width >
- vpfe_isif->formats[ISIF_PAD_SINK].width) ||
- (sel->r.top + sel->r.height >
- vpfe_isif->formats[ISIF_PAD_SINK].height)) {
- sel->r.left = 0;
- sel->r.top = 0;
- sel->r.width = format->width;
- sel->r.height = format->height;
- }
- /* adjust the width to 16 pixel boundary */
- sel->r.width = (sel->r.width + 15) & ~0xf;
- vpfe_isif->crop = sel->r;
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- isif_set_image_window(vpfe_isif);
- } else {
- struct v4l2_rect *rect;
-
- rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK);
- memcpy(rect, &vpfe_isif->crop, sizeof(*rect));
- }
- return 0;
-}
-
-/*
- * isif_pad_get_selection() - get crop rectangle on pad
- * @sd: VPFE isif V4L2 subdevice
- * @cfg: V4L2 subdev pad config
- * @code: pointer to v4l2_subdev_mbus_code_enum structure
- *
- * Return 0 on success, -EINVAL if pad is invalid
- */
-static int
-isif_pad_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_selection *sel)
-{
- struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
-
- /* check whether it's a valid pad and target */
- if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- struct v4l2_rect *rect;
-
- rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK);
- memcpy(&sel->r, rect, sizeof(*rect));
- } else {
- sel->r = vpfe_isif->crop;
- }
-
- return 0;
-}
-
-/*
- * isif_init_formats() - Initialize formats on all pads
- * @sd: VPFE isif V4L2 subdevice
- * @fh: V4L2 subdev file handle
- *
- * Initialize all pad formats with default values. Try formats are initialized
- * on the file handle.
- */
-static int
-isif_init_formats(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh)
-{
- struct v4l2_subdev_format format;
- struct v4l2_subdev_selection sel;
-
- memset(&format, 0, sizeof(format));
- format.pad = ISIF_PAD_SINK;
- format.which = V4L2_SUBDEV_FORMAT_TRY;
- format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
- format.format.width = MAX_WIDTH;
- format.format.height = MAX_HEIGHT;
- isif_set_format(sd, fh->pad, &format);
-
- memset(&format, 0, sizeof(format));
- format.pad = ISIF_PAD_SOURCE;
- format.which = V4L2_SUBDEV_FORMAT_TRY;
- format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
- format.format.width = MAX_WIDTH;
- format.format.height = MAX_HEIGHT;
- isif_set_format(sd, fh->pad, &format);
-
- memset(&sel, 0, sizeof(sel));
- sel.pad = ISIF_PAD_SINK;
- sel.which = V4L2_SUBDEV_FORMAT_TRY;
- sel.target = V4L2_SEL_TGT_CROP;
- sel.r.width = MAX_WIDTH;
- sel.r.height = MAX_HEIGHT;
- isif_pad_set_selection(sd, fh->pad, &sel);
-
- return 0;
-}
-
-/* subdev core operations */
-static const struct v4l2_subdev_core_ops isif_v4l2_core_ops = {
- .ioctl = isif_ioctl,
-};
-
-/* subdev file operations */
-static const struct v4l2_subdev_internal_ops isif_v4l2_internal_ops = {
- .open = isif_init_formats,
-};
-
-/* subdev video operations */
-static const struct v4l2_subdev_video_ops isif_v4l2_video_ops = {
- .s_stream = isif_set_stream,
-};
-
-/* subdev pad operations */
-static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = {
- .enum_mbus_code = isif_enum_mbus_code,
- .enum_frame_size = isif_enum_frame_size,
- .get_fmt = isif_get_format,
- .set_fmt = isif_set_format,
- .set_selection = isif_pad_set_selection,
- .get_selection = isif_pad_get_selection,
-};
-
-/* subdev operations */
-static const struct v4l2_subdev_ops isif_v4l2_ops = {
- .core = &isif_v4l2_core_ops,
- .video = &isif_v4l2_video_ops,
- .pad = &isif_v4l2_pad_ops,
-};
-
-/*
- * Media entity operations
- */
-
-/*
- * isif_link_setup() - Setup isif connections
- * @entity: isif media entity
- * @local: Pad at the local end of the link
- * @remote: Pad at the remote end of the link
- * @flags: Link flags
- *
- * return -EINVAL or zero on success
- */
-static int
-isif_link_setup(struct media_entity *entity, const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
- unsigned int index = local->index;
-
- /* FIXME: this is actually a hack! */
- if (is_media_entity_v4l2_subdev(remote->entity))
- index |= 2 << 16;
-
- switch (index) {
- case ISIF_PAD_SINK | 2 << 16:
- /* read from decoder/sensor */
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- isif->input = ISIF_INPUT_NONE;
- break;
- }
- if (isif->input != ISIF_INPUT_NONE)
- return -EBUSY;
- isif->input = ISIF_INPUT_PARALLEL;
- break;
-
- case ISIF_PAD_SOURCE:
- /* write to memory */
- if (flags & MEDIA_LNK_FL_ENABLED)
- isif->output = ISIF_OUTPUT_MEMORY;
- else
- isif->output = ISIF_OUTPUT_NONE;
- break;
-
- case ISIF_PAD_SOURCE | 2 << 16:
- if (flags & MEDIA_LNK_FL_ENABLED)
- isif->output = ISIF_OUTPUT_IPIPEIF;
- else
- isif->output = ISIF_OUTPUT_NONE;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-static const struct media_entity_operations isif_media_ops = {
- .link_setup = isif_link_setup,
-};
-
-/*
- * vpfe_isif_unregister_entities() - isif unregister entity
- * @isif - pointer to isif subdevice structure.
- */
-void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif)
-{
- vpfe_video_unregister(&isif->video_out);
- /* unregister subdev */
- v4l2_device_unregister_subdev(&isif->subdev);
- /* cleanup entity */
- media_entity_cleanup(&isif->subdev.entity);
-}
-
-static void isif_restore_defaults(struct vpfe_isif_device *isif)
-{
- enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
- int i;
-
- memset(&isif->isif_cfg.bayer.config_params, 0,
- sizeof(struct vpfe_isif_raw_config));
-
- isif->isif_cfg.bayer.config_params.linearize.corr_shft =
- VPFE_ISIF_NO_SHIFT;
- isif->isif_cfg.bayer.config_params.linearize.scale_fact.integer = 1;
- isif->isif_cfg.bayer.config_params.culling.hcpat_odd =
- ISIF_CULLING_HCAPT_ODD;
- isif->isif_cfg.bayer.config_params.culling.hcpat_even =
- ISIF_CULLING_HCAPT_EVEN;
- isif->isif_cfg.bayer.config_params.culling.vcpat = ISIF_CULLING_VCAPT;
- /* Enable clock to ISIF, IPIPEIF and BL */
- vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
- vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
- vpss_enable_clock(VPSS_BL_CLOCK, 1);
-
- /* set all registers to default value */
- for (i = 0; i <= 0x1f8; i += 4)
- isif_write(isif->isif_cfg.base_addr, 0, i);
- /* no culling support */
- isif_write(isif->isif_cfg.base_addr, 0xffff, CULH);
- isif_write(isif->isif_cfg.base_addr, 0xff, CULV);
-
- /* Set default offset and gain */
- isif_config_gain_offset(isif);
- vpss_select_ccdc_source(source);
-}
-
-/*
- * vpfe_isif_register_entities() - isif register entity
- * @isif - pointer to isif subdevice structure.
- * @vdev: pointer to v4l2 device structure.
- */
-int vpfe_isif_register_entities(struct vpfe_isif_device *isif,
- struct v4l2_device *vdev)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
- unsigned int flags;
- int ret;
-
- /* Register the subdev */
- ret = v4l2_device_register_subdev(vdev, &isif->subdev);
- if (ret < 0)
- return ret;
-
- isif_restore_defaults(isif);
- ret = vpfe_video_register(&isif->video_out, vdev);
- if (ret) {
- pr_err("Failed to register isif video out device\n");
- goto out_video_register;
- }
- isif->video_out.vpfe_dev = vpfe_dev;
- flags = 0;
- /* connect isif to video node */
- ret = media_create_pad_link(&isif->subdev.entity, 1,
- &isif->video_out.video_dev.entity,
- 0, flags);
- if (ret < 0)
- goto out_create_link;
- return 0;
-out_create_link:
- vpfe_video_unregister(&isif->video_out);
-out_video_register:
- v4l2_device_unregister_subdev(&isif->subdev);
- return ret;
-}
-
-/* -------------------------------------------------------------------
- * V4L2 subdev control operations
- */
-
-static int vpfe_isif_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct vpfe_isif_device *isif =
- container_of(ctrl->handler, struct vpfe_isif_device, ctrls);
- struct isif_oper_config *config = &isif->isif_cfg;
-
- switch (ctrl->id) {
- case VPFE_CID_DPCM_PREDICTOR:
- config->bayer.dpcm_predictor = ctrl->val;
- break;
-
- case VPFE_ISIF_CID_CRGAIN:
- config->isif_gain_params.cr_gain = ctrl->val;
- break;
-
- case VPFE_ISIF_CID_CGRGAIN:
- config->isif_gain_params.cgr_gain = ctrl->val;
- break;
-
- case VPFE_ISIF_CID_CGBGAIN:
- config->isif_gain_params.cgb_gain = ctrl->val;
- break;
-
- case VPFE_ISIF_CID_CBGAIN:
- config->isif_gain_params.cb_gain = ctrl->val;
- break;
-
- case VPFE_ISIF_CID_GAIN_OFFSET:
- config->isif_gain_params.offset = ctrl->val;
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static const struct v4l2_ctrl_ops vpfe_isif_ctrl_ops = {
- .s_ctrl = vpfe_isif_s_ctrl,
-};
-
-static const struct v4l2_ctrl_config vpfe_isif_dpcm_pred = {
- .ops = &vpfe_isif_ctrl_ops,
- .id = VPFE_CID_DPCM_PREDICTOR,
- .name = "DPCM Predictor",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = 1,
- .step = 1,
- .def = 0,
-};
-
-static const struct v4l2_ctrl_config vpfe_isif_crgain = {
- .ops = &vpfe_isif_ctrl_ops,
- .id = VPFE_ISIF_CID_CRGAIN,
- .name = "CRGAIN",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = (1 << 12) - 1,
- .step = 1,
- .def = 0,
-};
-
-static const struct v4l2_ctrl_config vpfe_isif_cgrgain = {
- .ops = &vpfe_isif_ctrl_ops,
- .id = VPFE_ISIF_CID_CGRGAIN,
- .name = "CGRGAIN",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = (1 << 12) - 1,
- .step = 1,
- .def = 0,
-};
-
-static const struct v4l2_ctrl_config vpfe_isif_cgbgain = {
- .ops = &vpfe_isif_ctrl_ops,
- .id = VPFE_ISIF_CID_CGBGAIN,
- .name = "CGBGAIN",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = (1 << 12) - 1,
- .step = 1,
- .def = 0,
-};
-
-static const struct v4l2_ctrl_config vpfe_isif_cbgain = {
- .ops = &vpfe_isif_ctrl_ops,
- .id = VPFE_ISIF_CID_CBGAIN,
- .name = "CBGAIN",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = (1 << 12) - 1,
- .step = 1,
- .def = 0,
-};
-
-static const struct v4l2_ctrl_config vpfe_isif_gain_offset = {
- .ops = &vpfe_isif_ctrl_ops,
- .id = VPFE_ISIF_CID_GAIN_OFFSET,
- .name = "Gain Offset",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = (1 << 12) - 1,
- .step = 1,
- .def = 0,
-};
-
-static void isif_remove(struct vpfe_isif_device *isif,
- struct platform_device *pdev)
-{
- struct resource *res;
- int i = 0;
-
- iounmap(isif->isif_cfg.base_addr);
- iounmap(isif->isif_cfg.linear_tbl0_addr);
- iounmap(isif->isif_cfg.linear_tbl1_addr);
-
- while (i < 3) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (res)
- release_mem_region(res->start,
- resource_size(res));
- i++;
- }
-}
-
-static void isif_config_defaults(struct vpfe_isif_device *isif)
-{
- isif->isif_cfg.ycbcr.v4l2_pix_fmt = V4L2_PIX_FMT_UYVY;
- isif->isif_cfg.ycbcr.pix_fmt = ISIF_PIXFMT_YCBCR_8BIT;
- isif->isif_cfg.ycbcr.frm_fmt = ISIF_FRMFMT_INTERLACED;
- isif->isif_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE;
- isif->isif_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE;
- isif->isif_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE;
- isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
- isif->isif_cfg.ycbcr.buf_type = ISIF_BUFTYPE_FLD_INTERLEAVED;
-
- isif->isif_cfg.bayer.v4l2_pix_fmt = V4L2_PIX_FMT_SGRBG10ALAW8;
- isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
- isif->isif_cfg.bayer.frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
- isif->isif_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE;
- isif->isif_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE;
- isif->isif_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE;
- isif->isif_cfg.bayer.cfa_pat = ISIF_CFA_PAT_MOSAIC;
- isif->isif_cfg.bayer.data_msb = ISIF_BIT_MSB_11;
- isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
-}
-/*
- * vpfe_isif_init() - Initialize V4L2 subdev and media entity
- * @isif: VPFE isif module
- * @pdev: Pointer to platform device structure.
- * Return 0 on success and a negative error code on failure.
- */
-int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev)
-{
- struct v4l2_subdev *sd = &isif->subdev;
- struct media_pad *pads = &isif->pads[0];
- struct media_entity *me = &sd->entity;
- static resource_size_t res_len;
- struct resource *res;
- void __iomem *addr;
- int status;
- int i = 0;
-
- /* Get the ISIF base address, linearization table0 and table1 addr. */
- while (i < 3) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res) {
- status = -ENOENT;
- goto fail_nobase_res;
- }
- res_len = resource_size(res);
- res = request_mem_region(res->start, res_len, res->name);
- if (!res) {
- status = -EBUSY;
- goto fail_nobase_res;
- }
- addr = ioremap_nocache(res->start, res_len);
- if (!addr) {
- status = -EBUSY;
- goto fail_base_iomap;
- }
- switch (i) {
- case 0:
- /* ISIF base address */
- isif->isif_cfg.base_addr = addr;
- break;
- case 1:
- /* ISIF linear tbl0 address */
- isif->isif_cfg.linear_tbl0_addr = addr;
- break;
- default:
- /* ISIF linear tbl0 address */
- isif->isif_cfg.linear_tbl1_addr = addr;
- break;
- }
- i++;
- }
- davinci_cfg_reg(DM365_VIN_CAM_WEN);
- davinci_cfg_reg(DM365_VIN_CAM_VD);
- davinci_cfg_reg(DM365_VIN_CAM_HD);
- davinci_cfg_reg(DM365_VIN_YIN4_7_EN);
- davinci_cfg_reg(DM365_VIN_YIN0_3_EN);
-
- /* queue ops */
- isif->video_out.ops = &isif_video_ops;
- v4l2_subdev_init(sd, &isif_v4l2_ops);
- sd->internal_ops = &isif_v4l2_internal_ops;
- strscpy(sd->name, "DAVINCI ISIF", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
- v4l2_set_subdevdata(sd, isif);
- sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
- pads[ISIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[ISIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-
- isif->input = ISIF_INPUT_NONE;
- isif->output = ISIF_OUTPUT_NONE;
- me->ops = &isif_media_ops;
- status = media_entity_pads_init(me, ISIF_PADS_NUM, pads);
- if (status)
- goto isif_fail;
- isif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- status = vpfe_video_init(&isif->video_out, "ISIF");
- if (status) {
- pr_err("Failed to init isif-out video device\n");
- goto isif_fail;
- }
- v4l2_ctrl_handler_init(&isif->ctrls, 6);
- v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_crgain, NULL);
- v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgrgain, NULL);
- v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgbgain, NULL);
- v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cbgain, NULL);
- v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_gain_offset, NULL);
- v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_dpcm_pred, NULL);
-
- v4l2_ctrl_handler_setup(&isif->ctrls);
- sd->ctrl_handler = &isif->ctrls;
- isif_config_defaults(isif);
- return 0;
-fail_base_iomap:
- release_mem_region(res->start, res_len);
- i--;
-fail_nobase_res:
- if (isif->isif_cfg.base_addr)
- iounmap(isif->isif_cfg.base_addr);
- if (isif->isif_cfg.linear_tbl0_addr)
- iounmap(isif->isif_cfg.linear_tbl0_addr);
-
- while (i >= 0) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- release_mem_region(res->start, res_len);
- i--;
- }
- return status;
-isif_fail:
- v4l2_ctrl_handler_free(&isif->ctrls);
- isif_remove(isif, pdev);
- return status;
-}
-
-/*
- * vpfe_isif_cleanup - isif module cleanup
- * @isif: pointer to isif subdevice
- * @dev: pointer to platform device structure
- */
-void
-vpfe_isif_cleanup(struct vpfe_isif_device *isif, struct platform_device *pdev)
-{
- isif_remove(isif, pdev);
-}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.h b/drivers/staging/media/davinci_vpfe/dm365_isif.h
deleted file mode 100644
index 0e1fe472fb2b..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_DM365_ISIF_H
-#define _DAVINCI_VPFE_DM365_ISIF_H
-
-#include <linux/platform_device.h>
-
-#include <mach/mux.h>
-
-#include <media/davinci/vpfe_types.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-
-#include "davinci_vpfe_user.h"
-#include "dm365_isif_regs.h"
-#include "vpfe_video.h"
-
-#define ISIF_CULLING_HCAPT_ODD 0xff
-#define ISIF_CULLING_HCAPT_EVEN 0xff
-#define ISIF_CULLING_VCAPT 0xff
-
-#define ISIF_CADU_BITS 0x07ff
-#define ISIF_CADL_BITS 0x0ffff
-
-enum isif_pixfmt {
- ISIF_PIXFMT_RAW = 0,
- ISIF_PIXFMT_YCBCR_16BIT = 1,
- ISIF_PIXFMT_YCBCR_8BIT = 2,
-};
-
-enum isif_frmfmt {
- ISIF_FRMFMT_PROGRESSIVE = 0,
- ISIF_FRMFMT_INTERLACED = 1,
-};
-
-/* PIXEL ORDER IN MEMORY from LSB to MSB */
-/* only applicable for 8-bit input mode */
-enum isif_pixorder {
- ISIF_PIXORDER_YCBYCR = 0,
- ISIF_PIXORDER_CBYCRY = 1,
-};
-
-enum isif_buftype {
- ISIF_BUFTYPE_FLD_INTERLEAVED = 0,
- ISIF_BUFTYPE_FLD_SEPARATED = 1,
-};
-
-struct isif_ycbcr_config {
- /* v4l2 pixel format */
- unsigned long v4l2_pix_fmt;
- /* isif pixel format */
- enum isif_pixfmt pix_fmt;
- /* isif frame format */
- enum isif_frmfmt frm_fmt;
- /* isif crop window */
- struct v4l2_rect win;
- /* field polarity */
- enum vpfe_pin_pol fid_pol;
- /* interface VD polarity */
- enum vpfe_pin_pol vd_pol;
- /* interface HD polarity */
- enum vpfe_pin_pol hd_pol;
- /* isif pix order. Only used for ycbcr capture */
- enum isif_pixorder pix_order;
- /* isif buffer type. Only used for ycbcr capture */
- enum isif_buftype buf_type;
-};
-
-enum isif_cfa_pattern {
- ISIF_CFA_PAT_MOSAIC = 0,
- ISIF_CFA_PAT_STRIPE = 1,
-};
-
-enum isif_data_msb {
- /* MSB b15 */
- ISIF_BIT_MSB_15 = 0,
- /* MSB b14 */
- ISIF_BIT_MSB_14 = 1,
- /* MSB b13 */
- ISIF_BIT_MSB_13 = 2,
- /* MSB b12 */
- ISIF_BIT_MSB_12 = 3,
- /* MSB b11 */
- ISIF_BIT_MSB_11 = 4,
- /* MSB b10 */
- ISIF_BIT_MSB_10 = 5,
- /* MSB b9 */
- ISIF_BIT_MSB_9 = 6,
- /* MSB b8 */
- ISIF_BIT_MSB_8 = 7,
- /* MSB b7 */
- ISIF_BIT_MSB_7 = 8,
-};
-
-struct isif_params_raw {
- /* v4l2 pixel format */
- unsigned long v4l2_pix_fmt;
- /* isif pixel format */
- enum isif_pixfmt pix_fmt;
- /* isif frame format */
- enum isif_frmfmt frm_fmt;
- /* video window */
- struct v4l2_rect win;
- /* field polarity */
- enum vpfe_pin_pol fid_pol;
- /* interface VD polarity */
- enum vpfe_pin_pol vd_pol;
- /* interface HD polarity */
- enum vpfe_pin_pol hd_pol;
- /* buffer type. Applicable for interlaced mode */
- enum isif_buftype buf_type;
- /* cfa pattern */
- enum isif_cfa_pattern cfa_pat;
- /* Data MSB position */
- enum isif_data_msb data_msb;
- /* Enable horizontal flip */
- unsigned char horz_flip_en;
- /* Enable image invert vertically */
- unsigned char image_invert_en;
- unsigned char dpcm_predictor;
- struct vpfe_isif_raw_config config_params;
-};
-
-enum isif_data_pack {
- ISIF_PACK_16BIT = 0,
- ISIF_PACK_12BIT = 1,
- ISIF_PACK_8BIT = 2,
-};
-
-struct isif_gain_values {
- unsigned int cr_gain;
- unsigned int cgr_gain;
- unsigned int cgb_gain;
- unsigned int cb_gain;
- unsigned int offset;
-};
-
-struct isif_oper_config {
- struct isif_ycbcr_config ycbcr;
- struct isif_params_raw bayer;
- enum isif_data_pack data_pack;
- struct isif_gain_values isif_gain_params;
- void __iomem *base_addr;
- void __iomem *linear_tbl0_addr;
- void __iomem *linear_tbl1_addr;
-};
-
-#define ISIF_PAD_SINK 0
-#define ISIF_PAD_SOURCE 1
-
-#define ISIF_PADS_NUM 2
-
-enum isif_input_entity {
- ISIF_INPUT_NONE = 0,
- ISIF_INPUT_PARALLEL = 1,
-};
-
-#define ISIF_OUTPUT_NONE (0)
-#define ISIF_OUTPUT_MEMORY (1 << 0)
-#define ISIF_OUTPUT_IPIPEIF (1 << 1)
-
-struct vpfe_isif_device {
- struct v4l2_subdev subdev;
- struct media_pad pads[ISIF_PADS_NUM];
- struct v4l2_mbus_framefmt formats[ISIF_PADS_NUM];
- enum isif_input_entity input;
- unsigned int output;
- struct v4l2_ctrl_handler ctrls;
- struct v4l2_rect crop;
- struct isif_oper_config isif_cfg;
- struct vpfe_video_device video_out;
-};
-
-enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev);
-void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif);
-int vpfe_isif_register_entities(struct vpfe_isif_device *isif,
- struct v4l2_device *dev);
-int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev);
-void vpfe_isif_cleanup(struct vpfe_isif_device *vpfe_isif,
- struct platform_device *pdev);
-void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif);
-void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif);
-
-#endif /* _DAVINCI_VPFE_DM365_ISIF_H */
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h b/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h
deleted file mode 100644
index 6695680817b9..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_DM365_ISIF_REGS_H
-#define _DAVINCI_VPFE_DM365_ISIF_REGS_H
-
-/* ISIF registers relative offsets */
-#define SYNCEN 0x00
-#define MODESET 0x04
-#define HDW 0x08
-#define VDW 0x0c
-#define PPLN 0x10
-#define LPFR 0x14
-#define SPH 0x18
-#define LNH 0x1c
-#define SLV0 0x20
-#define SLV1 0x24
-#define LNV 0x28
-#define CULH 0x2c
-#define CULV 0x30
-#define HSIZE 0x34
-#define SDOFST 0x38
-#define CADU 0x3c
-#define CADL 0x40
-#define LINCFG0 0x44
-#define LINCFG1 0x48
-#define CCOLP 0x4c
-#define CRGAIN 0x50
-#define CGRGAIN 0x54
-#define CGBGAIN 0x58
-#define CBGAIN 0x5c
-#define COFSTA 0x60
-#define FLSHCFG0 0x64
-#define FLSHCFG1 0x68
-#define FLSHCFG2 0x6c
-#define VDINT0 0x70
-#define VDINT1 0x74
-#define VDINT2 0x78
-#define MISC 0x7c
-#define CGAMMAWD 0x80
-#define REC656IF 0x84
-#define CCDCFG 0x88
-/*****************************************************
- * Defect Correction registers
- *****************************************************/
-#define DFCCTL 0x8c
-#define VDFSATLV 0x90
-#define DFCMEMCTL 0x94
-#define DFCMEM0 0x98
-#define DFCMEM1 0x9c
-#define DFCMEM2 0xa0
-#define DFCMEM3 0xa4
-#define DFCMEM4 0xa8
-/****************************************************
- * Black Clamp registers
- ****************************************************/
-#define CLAMPCFG 0xac
-#define CLDCOFST 0xb0
-#define CLSV 0xb4
-#define CLHWIN0 0xb8
-#define CLHWIN1 0xbc
-#define CLHWIN2 0xc0
-#define CLVRV 0xc4
-#define CLVWIN0 0xc8
-#define CLVWIN1 0xcc
-#define CLVWIN2 0xd0
-#define CLVWIN3 0xd4
-/****************************************************
- * Lense Shading Correction
- ****************************************************/
-#define DATAHOFST 0xd8
-#define DATAVOFST 0xdc
-#define LSCHVAL 0xe0
-#define LSCVVAL 0xe4
-#define TWODLSCCFG 0xe8
-#define TWODLSCOFST 0xec
-#define TWODLSCINI 0xf0
-#define TWODLSCGRBU 0xf4
-#define TWODLSCGRBL 0xf8
-#define TWODLSCGROF 0xfc
-#define TWODLSCORBU 0x100
-#define TWODLSCORBL 0x104
-#define TWODLSCOROF 0x108
-#define TWODLSCIRQEN 0x10c
-#define TWODLSCIRQST 0x110
-/****************************************************
- * Data formatter
- ****************************************************/
-#define FMTCFG 0x114
-#define FMTPLEN 0x118
-#define FMTSPH 0x11c
-#define FMTLNH 0x120
-#define FMTSLV 0x124
-#define FMTLNV 0x128
-#define FMTRLEN 0x12c
-#define FMTHCNT 0x130
-#define FMTAPTR_BASE 0x134
-/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */
-#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4))
-#define FMTPGMVF0 0x174
-#define FMTPGMVF1 0x178
-#define FMTPGMAPU0 0x17c
-#define FMTPGMAPU1 0x180
-#define FMTPGMAPS0 0x184
-#define FMTPGMAPS1 0x188
-#define FMTPGMAPS2 0x18c
-#define FMTPGMAPS3 0x190
-#define FMTPGMAPS4 0x194
-#define FMTPGMAPS5 0x198
-#define FMTPGMAPS6 0x19c
-#define FMTPGMAPS7 0x1a0
-/************************************************
- * Color Space Converter
- ************************************************/
-#define CSCCTL 0x1a4
-#define CSCM0 0x1a8
-#define CSCM1 0x1ac
-#define CSCM2 0x1b0
-#define CSCM3 0x1b4
-#define CSCM4 0x1b8
-#define CSCM5 0x1bc
-#define CSCM6 0x1c0
-#define CSCM7 0x1c4
-#define OBWIN0 0x1c8
-#define OBWIN1 0x1cc
-#define OBWIN2 0x1d0
-#define OBWIN3 0x1d4
-#define OBVAL0 0x1d8
-#define OBVAL1 0x1dc
-#define OBVAL2 0x1e0
-#define OBVAL3 0x1e4
-#define OBVAL4 0x1e8
-#define OBVAL5 0x1ec
-#define OBVAL6 0x1f0
-#define OBVAL7 0x1f4
-#define CLKCTL 0x1f8
-
-/* Masks & Shifts below */
-#define START_PX_HOR_MASK 0x7fff
-#define NUM_PX_HOR_MASK 0x7fff
-#define START_VER_ONE_MASK 0x7fff
-#define START_VER_TWO_MASK 0x7fff
-#define NUM_LINES_VER 0x7fff
-
-/* gain - offset masks */
-#define OFFSET_MASK 0xfff
-#define GAIN_SDRAM_EN_SHIFT 12
-#define GAIN_IPIPE_EN_SHIFT 13
-#define GAIN_H3A_EN_SHIFT 14
-#define OFST_SDRAM_EN_SHIFT 8
-#define OFST_IPIPE_EN_SHIFT 9
-#define OFST_H3A_EN_SHIFT 10
-#define GAIN_OFFSET_EN_MASK 0x7700
-
-/* Culling */
-#define CULL_PAT_EVEN_LINE_SHIFT 8
-
-/* CCDCFG register */
-#define ISIF_YCINSWP_RAW (0x00 << 4)
-#define ISIF_YCINSWP_YCBCR (0x01 << 4)
-#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6)
-#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8)
-#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9)
-#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10)
-#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15)
-#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15)
-#define ISIF_DATA_PACK_MASK 0x03
-#define ISIF_PIX_ORDER_SHIFT 11
-#define ISIF_PIX_ORDER_MASK 0x01
-#define ISIF_BW656_ENABLE (0x01 << 5)
-
-/* MODESET registers */
-#define ISIF_VDHDOUT_INPUT (0x00 << 0)
-#define ISIF_INPUT_MASK 0x03
-#define ISIF_INPUT_SHIFT 12
-#define ISIF_FID_POL_MASK 0x01
-#define ISIF_FID_POL_SHIFT 4
-#define ISIF_HD_POL_MASK 0x01
-#define ISIF_HD_POL_SHIFT 3
-#define ISIF_VD_POL_MASK 0x01
-#define ISIF_VD_POL_SHIFT 2
-#define ISIF_DATAPOL_NORMAL 0x00
-#define ISIF_DATAPOL_MASK 0x01
-#define ISIF_DATAPOL_SHIFT 6
-#define ISIF_EXWEN_DISABLE 0x00
-#define ISIF_EXWEN_MASK 0x01
-#define ISIF_EXWEN_SHIFT 5
-#define ISIF_FRM_FMT_MASK 0x01
-#define ISIF_FRM_FMT_SHIFT 7
-#define ISIF_DATASFT_MASK 0x07
-#define ISIF_DATASFT_SHIFT 8
-#define ISIF_LPF_SHIFT 14
-#define ISIF_LPF_MASK 0x1
-
-/* GAMMAWD registers */
-#define ISIF_ALAW_GAMA_WD_MASK 0xf
-#define ISIF_ALAW_GAMA_WD_SHIFT 1
-#define ISIF_ALAW_ENABLE 0x01
-#define ISIF_GAMMAWD_CFA_MASK 0x01
-#define ISIF_GAMMAWD_CFA_SHIFT 5
-
-/* HSIZE registers */
-#define ISIF_HSIZE_FLIP_MASK 0x01
-#define ISIF_HSIZE_FLIP_SHIFT 12
-#define ISIF_LINEOFST_MASK 0xfff
-
-/* MISC registers */
-#define ISIF_DPCM_EN_SHIFT 12
-#define ISIF_DPCM_PREDICTOR_SHIFT 13
-#define ISIF_DPCM_PREDICTOR_MASK 1
-
-/* Black clamp related */
-#define ISIF_BC_DCOFFSET_MASK 0x1fff
-#define ISIF_BC_MODE_COLOR_MASK 1
-#define ISIF_BC_MODE_COLOR_SHIFT 4
-#define ISIF_HORZ_BC_MODE_MASK 3
-#define ISIF_HORZ_BC_MODE_SHIFT 1
-#define ISIF_HORZ_BC_WIN_COUNT_MASK 0x1f
-#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5
-#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6
-#define ISIF_HORZ_BC_WIN_H_SIZE_MASK 3
-#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8
-#define ISIF_HORZ_BC_WIN_V_SIZE_MASK 3
-#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12
-#define ISIF_HORZ_BC_WIN_START_H_MASK 0x1fff
-#define ISIF_HORZ_BC_WIN_START_V_MASK 0x1fff
-#define ISIF_VERT_BC_OB_H_SZ_MASK 7
-#define ISIF_VERT_BC_RST_VAL_SEL_MASK 3
-#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4
-#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8
-#define ISIF_VERT_BC_OB_START_HORZ_MASK 0x1fff
-#define ISIF_VERT_BC_OB_START_VERT_MASK 0x1fff
-#define ISIF_VERT_BC_OB_VERT_SZ_MASK 0x1fff
-#define ISIF_VERT_BC_RST_VAL_MASK 0xfff
-#define ISIF_BC_VERT_START_SUB_V_MASK 0x1fff
-
-/* VDFC registers */
-#define ISIF_VDFC_EN_SHIFT 4
-#define ISIF_VDFC_CORR_MOD_MASK 3
-#define ISIF_VDFC_CORR_MOD_SHIFT 5
-#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7
-#define ISIF_VDFC_LEVEL_SHFT_MASK 7
-#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8
-#define ISIF_VDFC_SAT_LEVEL_MASK 0xfff
-#define ISIF_VDFC_POS_MASK 0x1fff
-#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2
-
-/* CSC registers */
-#define ISIF_CSC_COEF_INTEG_MASK 7
-#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f
-#define ISIF_CSC_COEF_INTEG_SHIFT 5
-#define ISIF_CSCM_MSB_SHIFT 8
-#define ISIF_DF_CSC_SPH_MASK 0x1fff
-#define ISIF_DF_CSC_LNH_MASK 0x1fff
-#define ISIF_DF_CSC_SLV_MASK 0x1fff
-#define ISIF_DF_CSC_LNV_MASK 0x1fff
-#define ISIF_DF_NUMLINES 0x7fff
-#define ISIF_DF_NUMPIX 0x1fff
-
-/* Offsets for LSC/DFC/Gain */
-#define ISIF_DATA_H_OFFSET_MASK 0x1fff
-#define ISIF_DATA_V_OFFSET_MASK 0x1fff
-
-/* Linearization */
-#define ISIF_LIN_CORRSFT_MASK 7
-#define ISIF_LIN_CORRSFT_SHIFT 4
-#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10
-#define ISIF_LIN_SCALE_FACT_DECIMAL_MASK 0x3ff
-#define ISIF_LIN_ENTRY_MASK 0x3ff
-
-/* masks and shifts*/
-#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0)
-#define ISIF_SYNCEN_WEN_MASK (1 << 1)
-#define ISIF_SYNCEN_WEN_SHIFT 1
-
-#endif /* _DAVINCI_VPFE_DM365_ISIF_REGS_H */
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
deleted file mode 100644
index 7adf1fae43f6..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c
+++ /dev/null
@@ -1,1995 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- *
- *
- * Resizer allows upscaling or downscaling a image to a desired
- * resolution. There are 2 resizer modules. both operating on the
- * same input image, but can have different output resolution.
- */
-
-#include "dm365_ipipe_hw.h"
-#include "dm365_resizer.h"
-
-#define MIN_IN_WIDTH 32
-#define MIN_IN_HEIGHT 32
-#define MAX_IN_WIDTH 4095
-#define MAX_IN_HEIGHT 4095
-#define MIN_OUT_WIDTH 16
-#define MIN_OUT_HEIGHT 2
-
-static const unsigned int resizer_input_formats[] = {
- MEDIA_BUS_FMT_UYVY8_2X8,
- MEDIA_BUS_FMT_Y8_1X8,
- MEDIA_BUS_FMT_UV8_1X8,
- MEDIA_BUS_FMT_SGRBG12_1X12,
-};
-
-static const unsigned int resizer_output_formats[] = {
- MEDIA_BUS_FMT_UYVY8_2X8,
- MEDIA_BUS_FMT_Y8_1X8,
- MEDIA_BUS_FMT_UV8_1X8,
- MEDIA_BUS_FMT_YDYUYDYV8_1X16,
- MEDIA_BUS_FMT_SGRBG12_1X12,
-};
-
-/* resizer_calculate_line_length() - This function calculates the line length of
- * various image planes at the input and
- * output.
- */
-static void
-resizer_calculate_line_length(u32 pix, int width, int height,
- int *line_len, int *line_len_c)
-{
- *line_len = 0;
- *line_len_c = 0;
-
- if (pix == MEDIA_BUS_FMT_UYVY8_2X8 ||
- pix == MEDIA_BUS_FMT_SGRBG12_1X12) {
- *line_len = width << 1;
- } else {
- *line_len = width;
- *line_len_c = width;
- }
-
- /* adjust the line len to be a multiple of 32 */
- *line_len += 31;
- *line_len &= ~0x1f;
- *line_len_c += 31;
- *line_len_c &= ~0x1f;
-}
-
-static inline int
-resizer_validate_output_image_format(struct device *dev,
- struct v4l2_mbus_framefmt *format,
- int *in_line_len, int *in_line_len_c)
-{
- if (format->code != MEDIA_BUS_FMT_UYVY8_2X8 &&
- format->code != MEDIA_BUS_FMT_Y8_1X8 &&
- format->code != MEDIA_BUS_FMT_UV8_1X8 &&
- format->code != MEDIA_BUS_FMT_YDYUYDYV8_1X16 &&
- format->code != MEDIA_BUS_FMT_SGRBG12_1X12) {
- dev_err(dev, "Invalid Mbus format, %d\n", format->code);
- return -EINVAL;
- }
- if (!format->width || !format->height) {
- dev_err(dev, "invalid width or height\n");
- return -EINVAL;
- }
- resizer_calculate_line_length(format->code, format->width,
- format->height, in_line_len, in_line_len_c);
- return 0;
-}
-
-static void
-resizer_configure_passthru(struct vpfe_resizer_device *resizer, int bypass)
-{
- struct resizer_params *param = &resizer->config;
-
- param->rsz_rsc_param[RSZ_A].cen = DISABLE;
- param->rsz_rsc_param[RSZ_A].yen = DISABLE;
- param->rsz_rsc_param[RSZ_A].v_phs_y = 0;
- param->rsz_rsc_param[RSZ_A].v_phs_c = 0;
- param->rsz_rsc_param[RSZ_A].v_dif = 256;
- param->rsz_rsc_param[RSZ_A].v_lpf_int_y = 0;
- param->rsz_rsc_param[RSZ_A].v_lpf_int_c = 0;
- param->rsz_rsc_param[RSZ_A].h_phs = 0;
- param->rsz_rsc_param[RSZ_A].h_dif = 256;
- param->rsz_rsc_param[RSZ_A].h_lpf_int_y = 0;
- param->rsz_rsc_param[RSZ_A].h_lpf_int_c = 0;
- param->rsz_rsc_param[RSZ_A].dscale_en = DISABLE;
- param->rsz2rgb[RSZ_A].rgb_en = DISABLE;
- param->rsz_en[RSZ_A] = ENABLE;
- param->rsz_en[RSZ_B] = DISABLE;
- if (bypass) {
- param->rsz_rsc_param[RSZ_A].i_vps = 0;
- param->rsz_rsc_param[RSZ_A].i_hps = 0;
- /* Raw Bypass */
- param->rsz_common.passthrough = BYPASS_ON;
- }
-}
-
-static void
-configure_resizer_out_params(struct vpfe_resizer_device *resizer, int index,
- void *output_spec, unsigned char partial,
- unsigned int flag)
-{
- struct resizer_params *param = &resizer->config;
- struct v4l2_mbus_framefmt *outformat;
- struct vpfe_rsz_output_spec *output;
-
- if (index == RSZ_A &&
- resizer->resizer_a.output == RESIZER_OUTPUT_NONE) {
- param->rsz_en[index] = DISABLE;
- return;
- }
- if (index == RSZ_B &&
- resizer->resizer_b.output == RESIZER_OUTPUT_NONE) {
- param->rsz_en[index] = DISABLE;
- return;
- }
- output = output_spec;
- param->rsz_en[index] = ENABLE;
- if (partial) {
- param->rsz_rsc_param[index].h_flip = output->h_flip;
- param->rsz_rsc_param[index].v_flip = output->v_flip;
- param->rsz_rsc_param[index].v_typ_y = output->v_typ_y;
- param->rsz_rsc_param[index].v_typ_c = output->v_typ_c;
- param->rsz_rsc_param[index].v_lpf_int_y =
- output->v_lpf_int_y;
- param->rsz_rsc_param[index].v_lpf_int_c =
- output->v_lpf_int_c;
- param->rsz_rsc_param[index].h_typ_y = output->h_typ_y;
- param->rsz_rsc_param[index].h_typ_c = output->h_typ_c;
- param->rsz_rsc_param[index].h_lpf_int_y =
- output->h_lpf_int_y;
- param->rsz_rsc_param[index].h_lpf_int_c =
- output->h_lpf_int_c;
- param->rsz_rsc_param[index].dscale_en =
- output->en_down_scale;
- param->rsz_rsc_param[index].h_dscale_ave_sz =
- output->h_dscale_ave_sz;
- param->rsz_rsc_param[index].v_dscale_ave_sz =
- output->v_dscale_ave_sz;
- param->ext_mem_param[index].user_y_ofst =
- (output->user_y_ofst + 31) & ~0x1f;
- param->ext_mem_param[index].user_c_ofst =
- (output->user_c_ofst + 31) & ~0x1f;
- return;
- }
-
- if (index == RSZ_A)
- outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
- else
- outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
- param->rsz_rsc_param[index].o_vsz = outformat->height - 1;
- param->rsz_rsc_param[index].o_hsz = outformat->width - 1;
- param->ext_mem_param[index].rsz_sdr_ptr_s_y = output->vst_y;
- param->ext_mem_param[index].rsz_sdr_ptr_e_y = outformat->height;
- param->ext_mem_param[index].rsz_sdr_ptr_s_c = output->vst_c;
- param->ext_mem_param[index].rsz_sdr_ptr_e_c = outformat->height;
-
- if (!flag)
- return;
- /* update common parameters */
- param->rsz_rsc_param[index].h_flip = output->h_flip;
- param->rsz_rsc_param[index].v_flip = output->v_flip;
- param->rsz_rsc_param[index].v_typ_y = output->v_typ_y;
- param->rsz_rsc_param[index].v_typ_c = output->v_typ_c;
- param->rsz_rsc_param[index].v_lpf_int_y = output->v_lpf_int_y;
- param->rsz_rsc_param[index].v_lpf_int_c = output->v_lpf_int_c;
- param->rsz_rsc_param[index].h_typ_y = output->h_typ_y;
- param->rsz_rsc_param[index].h_typ_c = output->h_typ_c;
- param->rsz_rsc_param[index].h_lpf_int_y = output->h_lpf_int_y;
- param->rsz_rsc_param[index].h_lpf_int_c = output->h_lpf_int_c;
- param->rsz_rsc_param[index].dscale_en = output->en_down_scale;
- param->rsz_rsc_param[index].h_dscale_ave_sz = output->h_dscale_ave_sz;
- param->rsz_rsc_param[index].v_dscale_ave_sz = output->h_dscale_ave_sz;
- param->ext_mem_param[index].user_y_ofst =
- (output->user_y_ofst + 31) & ~0x1f;
- param->ext_mem_param[index].user_c_ofst =
- (output->user_c_ofst + 31) & ~0x1f;
-}
-
-/*
- * resizer_calculate_resize_ratios() - Calculates resize ratio for resizer
- * A or B. This is called after setting
- * the input size or output size.
- * @resizer: Pointer to VPFE resizer subdevice.
- * @index: index RSZ_A-resizer-A RSZ_B-resizer-B.
- */
-static void
-resizer_calculate_resize_ratios(struct vpfe_resizer_device *resizer, int index)
-{
- struct resizer_params *param = &resizer->config;
- struct v4l2_mbus_framefmt *informat, *outformat;
-
- informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
-
- if (index == RSZ_A)
- outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
- else
- outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
-
- if (outformat->field != V4L2_FIELD_INTERLACED)
- param->rsz_rsc_param[index].v_dif =
- ((informat->height) * 256) / (outformat->height);
- else
- param->rsz_rsc_param[index].v_dif =
- ((informat->height >> 1) * 256) / (outformat->height);
- param->rsz_rsc_param[index].h_dif =
- ((informat->width) * 256) / (outformat->width);
-}
-
-static void resizer_enable_422_420_conversion(struct resizer_params *param,
- int index, bool en)
-{
- param->rsz_rsc_param[index].cen = en;
- param->rsz_rsc_param[index].yen = en;
-}
-
-/* resizer_calculate_sdram_offsets() - This function calculates the offsets from
- * start of buffer for the C plane when
- * output format is YUV420SP. It also
- * calculates the offsets from the start of
- * the buffer when the image is flipped
- * vertically or horizontally for ycbcr/y/c
- * planes.
- * @resizer: Pointer to resizer subdevice.
- * @index: index RSZ_A-resizer-A RSZ_B-resizer-B.
- */
-static int
-resizer_calculate_sdram_offsets(struct vpfe_resizer_device *resizer, int index)
-{
- struct resizer_params *param = &resizer->config;
- struct v4l2_mbus_framefmt *outformat;
- int bytesperpixel = 2;
- int image_height;
- int image_width;
- int yuv_420 = 0;
- int offset = 0;
-
- if (index == RSZ_A)
- outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
- else
- outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
-
- image_height = outformat->height + 1;
- image_width = outformat->width + 1;
- param->ext_mem_param[index].c_offset = 0;
- param->ext_mem_param[index].flip_ofst_y = 0;
- param->ext_mem_param[index].flip_ofst_c = 0;
- if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) {
- /* YUV 420 */
- yuv_420 = 1;
- bytesperpixel = 1;
- }
-
- if (param->rsz_rsc_param[index].h_flip)
- /* width * bytesperpixel - 1 */
- offset = (image_width * bytesperpixel) - 1;
- if (param->rsz_rsc_param[index].v_flip)
- offset += (image_height - 1) *
- param->ext_mem_param[index].rsz_sdr_oft_y;
- param->ext_mem_param[index].flip_ofst_y = offset;
- if (!yuv_420)
- return 0;
- offset = 0;
- /* half height for c-plane */
- if (param->rsz_rsc_param[index].h_flip)
- /* width * bytesperpixel - 1 */
- offset = image_width - 1;
- if (param->rsz_rsc_param[index].v_flip)
- offset += (((image_height >> 1) - 1) *
- param->ext_mem_param[index].rsz_sdr_oft_c);
- param->ext_mem_param[index].flip_ofst_c = offset;
- param->ext_mem_param[index].c_offset =
- param->ext_mem_param[index].rsz_sdr_oft_y * image_height;
- return 0;
-}
-
-static int resizer_configure_output_win(struct vpfe_resizer_device *resizer)
-{
- struct resizer_params *param = &resizer->config;
- struct vpfe_rsz_output_spec output_specs;
- struct v4l2_mbus_framefmt *outformat;
- int line_len_c;
- int line_len;
- int ret;
-
- outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
-
- memset(&output_specs, 0x0, sizeof(struct vpfe_rsz_output_spec));
- output_specs.vst_y = param->user_config.vst;
- if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
- output_specs.vst_c = param->user_config.vst;
-
- configure_resizer_out_params(resizer, RSZ_A, &output_specs, 0, 0);
- resizer_calculate_line_length(outformat->code,
- param->rsz_rsc_param[0].o_hsz + 1,
- param->rsz_rsc_param[0].o_vsz + 1,
- &line_len, &line_len_c);
- param->ext_mem_param[0].rsz_sdr_oft_y = line_len;
- param->ext_mem_param[0].rsz_sdr_oft_c = line_len_c;
- resizer_calculate_resize_ratios(resizer, RSZ_A);
- if (param->rsz_en[RSZ_B])
- resizer_calculate_resize_ratios(resizer, RSZ_B);
-
- if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
- resizer_enable_422_420_conversion(param, RSZ_A, ENABLE);
- else
- resizer_enable_422_420_conversion(param, RSZ_A, DISABLE);
-
- ret = resizer_calculate_sdram_offsets(resizer, RSZ_A);
- if (!ret && param->rsz_en[RSZ_B])
- ret = resizer_calculate_sdram_offsets(resizer, RSZ_B);
-
- if (ret)
- pr_err("Error in calculating sdram offsets\n");
- return ret;
-}
-
-static int
-resizer_calculate_down_scale_f_div_param(struct device *dev,
- int input_width, int output_width,
- struct resizer_scale_param *param)
-{
- /* rsz = R, input_width = H, output width = h in the equation */
- unsigned int two_power;
- unsigned int upper_h1;
- unsigned int upper_h2;
- unsigned int val1;
- unsigned int val;
- unsigned int rsz;
- unsigned int h1;
- unsigned int h2;
- unsigned int o;
- unsigned int n;
-
- upper_h1 = input_width >> 1;
- n = param->h_dscale_ave_sz;
- /* 2 ^ (scale+1) */
- two_power = 1 << (n + 1);
- upper_h1 = (upper_h1 >> (n + 1)) << (n + 1);
- upper_h2 = input_width - upper_h1;
- if (upper_h2 % two_power) {
- dev_err(dev, "frame halves to be a multiple of 2 power n+1\n");
- return -EINVAL;
- }
- two_power = 1 << n;
- rsz = (input_width << 8) / output_width;
- val = rsz * two_power;
- val = ((upper_h1 << 8) / val) + 1;
- if (!(val % 2)) {
- h1 = val;
- } else {
- val = upper_h1 << 8;
- val >>= n + 1;
- val -= rsz >> 1;
- val /= rsz << 1;
- val <<= 1;
- val += 2;
- h1 = val;
- }
- o = 10 + (two_power << 2);
- if (((input_width << 7) / rsz) % 2)
- o += ((DIV_ROUND_UP(rsz, 1024) << 1) << n);
- h2 = output_width - h1;
- /* phi */
- val = (h1 * rsz) - (((upper_h1 - (o - 10)) / two_power) << 8);
- /* skip */
- val1 = ((val - 1024) >> 9) << 1;
- param->f_div.num_passes = MAX_PASSES;
- param->f_div.pass[0].o_hsz = h1 - 1;
- param->f_div.pass[0].i_hps = 0;
- param->f_div.pass[0].h_phs = 0;
- param->f_div.pass[0].src_hps = 0;
- param->f_div.pass[0].src_hsz = upper_h1 + o;
- param->f_div.pass[1].o_hsz = h2 - 1;
- param->f_div.pass[1].i_hps = 10 + (val1 * two_power);
- param->f_div.pass[1].h_phs = val - (val1 << 8);
- param->f_div.pass[1].src_hps = upper_h1 - o;
- param->f_div.pass[1].src_hsz = upper_h2 + o;
-
- return 0;
-}
-
-static int
-resizer_configure_common_in_params(struct vpfe_resizer_device *resizer)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- struct resizer_params *param = &resizer->config;
- struct vpfe_rsz_config_params *user_config;
- struct v4l2_mbus_framefmt *informat;
-
- informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
- user_config = &resizer->config.user_config;
- param->rsz_common.vps = param->user_config.vst;
- param->rsz_common.hps = param->user_config.hst;
-
- if (vpfe_ipipeif_decimation_enabled(vpfe_dev))
- param->rsz_common.hsz = ((informat->width - 1) *
- IPIPEIF_RSZ_CONST) / vpfe_ipipeif_get_rsz(vpfe_dev);
- else
- param->rsz_common.hsz = informat->width - 1;
-
- if (informat->field == V4L2_FIELD_INTERLACED)
- param->rsz_common.vsz = (informat->height - 1) >> 1;
- else
- param->rsz_common.vsz = informat->height - 1;
-
- param->rsz_common.raw_flip = 0;
-
- if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF)
- param->rsz_common.source = IPIPEIF_DATA;
- else
- param->rsz_common.source = IPIPE_DATA;
-
- switch (informat->code) {
- case MEDIA_BUS_FMT_UYVY8_2X8:
- param->rsz_common.src_img_fmt = RSZ_IMG_422;
- param->rsz_common.raw_flip = 0;
- break;
-
- case MEDIA_BUS_FMT_Y8_1X8:
- param->rsz_common.src_img_fmt = RSZ_IMG_420;
- /* Select y */
- param->rsz_common.y_c = 0;
- param->rsz_common.raw_flip = 0;
- break;
-
- case MEDIA_BUS_FMT_UV8_1X8:
- param->rsz_common.src_img_fmt = RSZ_IMG_420;
- /* Select y */
- param->rsz_common.y_c = 1;
- param->rsz_common.raw_flip = 0;
- break;
-
- case MEDIA_BUS_FMT_SGRBG12_1X12:
- param->rsz_common.raw_flip = 1;
- break;
-
- default:
- param->rsz_common.src_img_fmt = RSZ_IMG_422;
- param->rsz_common.source = IPIPE_DATA;
- }
-
- param->rsz_common.yuv_y_min = user_config->yuv_y_min;
- param->rsz_common.yuv_y_max = user_config->yuv_y_max;
- param->rsz_common.yuv_c_min = user_config->yuv_c_min;
- param->rsz_common.yuv_c_max = user_config->yuv_c_max;
- param->rsz_common.out_chr_pos = user_config->out_chr_pos;
- param->rsz_common.rsz_seq_crv = user_config->chroma_sample_even;
-
- return 0;
-}
-static int
-resizer_configure_in_continuous_mode(struct vpfe_resizer_device *resizer)
-{
- struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
- struct resizer_params *param = &resizer->config;
- struct vpfe_rsz_config_params *cont_config;
- int line_len_c;
- int line_len;
- int ret;
-
- if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY) {
- dev_err(dev, "enable resizer - Resizer-A\n");
- return -EINVAL;
- }
-
- cont_config = &resizer->config.user_config;
- param->rsz_en[RSZ_A] = ENABLE;
- configure_resizer_out_params(resizer, RSZ_A,
- &cont_config->output1, 1, 0);
- param->rsz_en[RSZ_B] = DISABLE;
- param->oper_mode = RESIZER_MODE_CONTINUOUS;
-
- if (resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) {
- struct v4l2_mbus_framefmt *outformat2;
-
- param->rsz_en[RSZ_B] = ENABLE;
- outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
- ret = resizer_validate_output_image_format(dev, outformat2,
- &line_len, &line_len_c);
- if (ret)
- return ret;
- param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
- param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
- configure_resizer_out_params(resizer, RSZ_B,
- &cont_config->output2, 0, 1);
- if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
- resizer_enable_422_420_conversion(param,
- RSZ_B, ENABLE);
- else
- resizer_enable_422_420_conversion(param,
- RSZ_B, DISABLE);
- }
- resizer_configure_common_in_params(resizer);
- ret = resizer_configure_output_win(resizer);
- if (ret)
- return ret;
-
- param->rsz_common.passthrough = cont_config->bypass;
- if (cont_config->bypass)
- resizer_configure_passthru(resizer, 1);
-
- return 0;
-}
-
-static inline int
-resizer_validate_input_image_format(struct device *dev,
- u32 pix,
- int width, int height, int *line_len)
-{
- int val;
-
- if (pix != MEDIA_BUS_FMT_UYVY8_2X8 &&
- pix != MEDIA_BUS_FMT_Y8_1X8 &&
- pix != MEDIA_BUS_FMT_UV8_1X8 &&
- pix != MEDIA_BUS_FMT_SGRBG12_1X12) {
- dev_err(dev,
- "resizer validate output: pix format not supported, %d\n", pix);
- return -EINVAL;
- }
-
- if (!width || !height) {
- dev_err(dev,
- "resizer validate input: invalid width or height\n");
- return -EINVAL;
- }
-
- if (pix == MEDIA_BUS_FMT_UV8_1X8)
- resizer_calculate_line_length(pix, width,
- height, &val, line_len);
- else
- resizer_calculate_line_length(pix, width,
- height, line_len, &val);
-
- return 0;
-}
-
-static int
-resizer_validate_decimation(struct device *dev, enum ipipeif_decimation dec_en,
- unsigned char rsz, unsigned char frame_div_mode_en,
- int width)
-{
- if (dec_en && frame_div_mode_en) {
- dev_err(dev,
- "dec_en & frame_div_mode_en can not enabled simultaneously\n");
- return -EINVAL;
- }
-
- if (frame_div_mode_en) {
- dev_err(dev, "frame_div_mode mode not supported\n");
- return -EINVAL;
- }
-
- if (!dec_en)
- return 0;
-
- if (width <= VPFE_IPIPE_MAX_INPUT_WIDTH) {
- dev_err(dev,
- "image width to be more than %d for decimation\n",
- VPFE_IPIPE_MAX_INPUT_WIDTH);
- return -EINVAL;
- }
-
- if (rsz < IPIPEIF_RSZ_MIN || rsz > IPIPEIF_RSZ_MAX) {
- dev_err(dev, "rsz range is %d to %d\n",
- IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* resizer_calculate_normal_f_div_param() - Algorithm to calculate the frame
- * division parameters for resizer.
- * in normal mode.
- */
-static int
-resizer_calculate_normal_f_div_param(struct device *dev, int input_width,
- int output_width, struct resizer_scale_param *param)
-{
- /* rsz = R, input_width = H, output width = h in the equation */
- unsigned int val1;
- unsigned int rsz;
- unsigned int val;
- unsigned int h1;
- unsigned int h2;
- unsigned int o;
-
- if (output_width > input_width) {
- dev_err(dev, "frame div mode is used for scale down only\n");
- return -EINVAL;
- }
-
- rsz = (input_width << 8) / output_width;
- val = rsz << 1;
- val = ((input_width << 8) / val) + 1;
- o = 14;
- if (!(val % 2)) {
- h1 = val;
- } else {
- val = input_width << 7;
- val -= rsz >> 1;
- val /= rsz << 1;
- val <<= 1;
- val += 2;
- o += (DIV_ROUND_UP(rsz, 1024) << 1);
- h1 = val;
- }
- h2 = output_width - h1;
- /* phi */
- val = (h1 * rsz) - (((input_width >> 1) - o) << 8);
- /* skip */
- val1 = ((val - 1024) >> 9) << 1;
- param->f_div.num_passes = MAX_PASSES;
- param->f_div.pass[0].o_hsz = h1 - 1;
- param->f_div.pass[0].i_hps = 0;
- param->f_div.pass[0].h_phs = 0;
- param->f_div.pass[0].src_hps = 0;
- param->f_div.pass[0].src_hsz = (input_width >> 2) + o;
- param->f_div.pass[1].o_hsz = h2 - 1;
- param->f_div.pass[1].i_hps = val1;
- param->f_div.pass[1].h_phs = val - (val1 << 8);
- param->f_div.pass[1].src_hps = (input_width >> 2) - o;
- param->f_div.pass[1].src_hsz = (input_width >> 2) + o;
-
- return 0;
-}
-
-static int
-resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer)
-{
- struct vpfe_rsz_config_params *config = &resizer->config.user_config;
- struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- struct v4l2_mbus_framefmt *outformat1, *outformat2;
- struct resizer_params *param = &resizer->config;
- struct v4l2_mbus_framefmt *informat;
- int decimation;
- int line_len_c;
- int line_len;
- int rsz;
- int ret;
-
- informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
- outformat1 = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
- outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
-
- decimation = vpfe_ipipeif_decimation_enabled(vpfe_dev);
- rsz = vpfe_ipipeif_get_rsz(vpfe_dev);
- if (decimation && param->user_config.frame_div_mode_en) {
- dev_err(dev,
- "dec_en & frame_div_mode_en cannot enabled simultaneously\n");
- return -EINVAL;
- }
-
- ret = resizer_validate_decimation(dev, decimation, rsz,
- param->user_config.frame_div_mode_en, informat->width);
- if (ret)
- return -EINVAL;
-
- ret = resizer_validate_input_image_format(dev, informat->code,
- informat->width, informat->height, &line_len);
- if (ret)
- return -EINVAL;
-
- if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
- param->rsz_en[RSZ_A] = ENABLE;
- ret = resizer_validate_output_image_format(dev, outformat1,
- &line_len, &line_len_c);
- if (ret)
- return ret;
- param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len;
- param->ext_mem_param[RSZ_A].rsz_sdr_oft_c = line_len_c;
- configure_resizer_out_params(resizer, RSZ_A,
- &param->user_config.output1, 0, 1);
-
- if (outformat1->code == MEDIA_BUS_FMT_SGRBG12_1X12)
- param->rsz_common.raw_flip = 1;
- else
- param->rsz_common.raw_flip = 0;
-
- if (outformat1->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
- resizer_enable_422_420_conversion(param,
- RSZ_A, ENABLE);
- else
- resizer_enable_422_420_conversion(param,
- RSZ_A, DISABLE);
- }
-
- if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
- param->rsz_en[RSZ_B] = ENABLE;
- ret = resizer_validate_output_image_format(dev, outformat2,
- &line_len, &line_len_c);
- if (ret)
- return ret;
- param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
- param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
- configure_resizer_out_params(resizer, RSZ_B,
- &param->user_config.output2, 0, 1);
- if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
- resizer_enable_422_420_conversion(param,
- RSZ_B, ENABLE);
- else
- resizer_enable_422_420_conversion(param,
- RSZ_B, DISABLE);
- }
-
- resizer_configure_common_in_params(resizer);
- if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
- resizer_calculate_resize_ratios(resizer, RSZ_A);
- resizer_calculate_sdram_offsets(resizer, RSZ_A);
- /* Overriding resize ratio calculation */
- if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
- param->rsz_rsc_param[RSZ_A].v_dif =
- (((informat->height + 1) * 2) * 256) /
- (param->rsz_rsc_param[RSZ_A].o_vsz + 1);
- }
- }
-
- if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
- resizer_calculate_resize_ratios(resizer, RSZ_B);
- resizer_calculate_sdram_offsets(resizer, RSZ_B);
- /* Overriding resize ratio calculation */
- if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
- param->rsz_rsc_param[RSZ_B].v_dif =
- (((informat->height + 1) * 2) * 256) /
- (param->rsz_rsc_param[RSZ_B].o_vsz + 1);
- }
- }
- if (param->user_config.frame_div_mode_en &&
- param->rsz_en[RSZ_A]) {
- if (!param->rsz_rsc_param[RSZ_A].dscale_en)
- ret = resizer_calculate_normal_f_div_param(dev,
- informat->width,
- param->rsz_rsc_param[RSZ_A].o_vsz + 1,
- &param->rsz_rsc_param[RSZ_A]);
- else
- ret = resizer_calculate_down_scale_f_div_param(dev,
- informat->width,
- param->rsz_rsc_param[RSZ_A].o_vsz + 1,
- &param->rsz_rsc_param[RSZ_A]);
- if (ret)
- return -EINVAL;
- }
- if (param->user_config.frame_div_mode_en &&
- param->rsz_en[RSZ_B]) {
- if (!param->rsz_rsc_param[RSZ_B].dscale_en)
- ret = resizer_calculate_normal_f_div_param(dev,
- informat->width,
- param->rsz_rsc_param[RSZ_B].o_vsz + 1,
- &param->rsz_rsc_param[RSZ_B]);
- else
- ret = resizer_calculate_down_scale_f_div_param(dev,
- informat->width,
- param->rsz_rsc_param[RSZ_B].o_vsz + 1,
- &param->rsz_rsc_param[RSZ_B]);
- if (ret)
- return -EINVAL;
- }
- param->rsz_common.passthrough = config->bypass;
- if (config->bypass)
- resizer_configure_passthru(resizer, 1);
- return 0;
-}
-
-static void
-resizer_set_default_configuration(struct vpfe_resizer_device *resizer)
-{
-#define WIDTH_I 640
-#define HEIGHT_I 480
-#define WIDTH_O 640
-#define HEIGHT_O 480
- const struct resizer_params rsz_default_config = {
- .oper_mode = RESIZER_MODE_ONE_SHOT,
- .rsz_common = {
- .vsz = HEIGHT_I - 1,
- .hsz = WIDTH_I - 1,
- .src_img_fmt = RSZ_IMG_422,
- .raw_flip = 1, /* flip preserve Raw format */
- .source = IPIPE_DATA,
- .passthrough = BYPASS_OFF,
- .yuv_y_max = 255,
- .yuv_c_max = 255,
- .rsz_seq_crv = DISABLE,
- .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE,
- },
- .rsz_rsc_param = {
- {
- .h_flip = DISABLE,
- .v_flip = DISABLE,
- .cen = DISABLE,
- .yen = DISABLE,
- .o_vsz = HEIGHT_O - 1,
- .o_hsz = WIDTH_O - 1,
- .v_dif = 256,
- .v_typ_y = VPFE_RSZ_INTP_CUBIC,
- .v_typ_c = VPFE_RSZ_INTP_CUBIC,
- .h_dif = 256,
- .h_typ_y = VPFE_RSZ_INTP_CUBIC,
- .h_typ_c = VPFE_RSZ_INTP_CUBIC,
- .h_dscale_ave_sz =
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- .v_dscale_ave_sz =
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- },
- {
- .h_flip = DISABLE,
- .v_flip = DISABLE,
- .cen = DISABLE,
- .yen = DISABLE,
- .o_vsz = HEIGHT_O - 1,
- .o_hsz = WIDTH_O - 1,
- .v_dif = 256,
- .v_typ_y = VPFE_RSZ_INTP_CUBIC,
- .v_typ_c = VPFE_RSZ_INTP_CUBIC,
- .h_dif = 256,
- .h_typ_y = VPFE_RSZ_INTP_CUBIC,
- .h_typ_c = VPFE_RSZ_INTP_CUBIC,
- .h_dscale_ave_sz =
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- .v_dscale_ave_sz =
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- },
- },
- .rsz2rgb = {
- {
- .rgb_en = DISABLE
- },
- {
- .rgb_en = DISABLE
- }
- },
- .ext_mem_param = {
- {
- .rsz_sdr_oft_y = WIDTH_O << 1,
- .rsz_sdr_ptr_e_y = HEIGHT_O,
- .rsz_sdr_oft_c = WIDTH_O,
- .rsz_sdr_ptr_e_c = HEIGHT_O >> 1,
- },
- {
- .rsz_sdr_oft_y = WIDTH_O << 1,
- .rsz_sdr_ptr_e_y = HEIGHT_O,
- .rsz_sdr_oft_c = WIDTH_O,
- .rsz_sdr_ptr_e_c = HEIGHT_O,
- },
- },
- .rsz_en[0] = ENABLE,
- .rsz_en[1] = DISABLE,
- .user_config = {
- .output1 = {
- .v_typ_y = VPFE_RSZ_INTP_CUBIC,
- .v_typ_c = VPFE_RSZ_INTP_CUBIC,
- .h_typ_y = VPFE_RSZ_INTP_CUBIC,
- .h_typ_c = VPFE_RSZ_INTP_CUBIC,
- .h_dscale_ave_sz =
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- .v_dscale_ave_sz =
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- },
- .output2 = {
- .v_typ_y = VPFE_RSZ_INTP_CUBIC,
- .v_typ_c = VPFE_RSZ_INTP_CUBIC,
- .h_typ_y = VPFE_RSZ_INTP_CUBIC,
- .h_typ_c = VPFE_RSZ_INTP_CUBIC,
- .h_dscale_ave_sz =
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- .v_dscale_ave_sz =
- VPFE_IPIPE_DWN_SCALE_1_OVER_2,
- },
- .yuv_y_max = 255,
- .yuv_c_max = 255,
- .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE,
- },
- };
- memcpy(&resizer->config, &rsz_default_config,
- sizeof(struct resizer_params));
-}
-
-/*
- * resizer_set_configuration() - set resizer config
- * @resizer: vpfe resizer device pointer.
- * @chan_config: resizer channel configuration.
- */
-static int
-resizer_set_configuration(struct vpfe_resizer_device *resizer,
- struct vpfe_rsz_config *chan_config)
-{
- if (!chan_config->config)
- resizer_set_default_configuration(resizer);
- else
- if (copy_from_user(&resizer->config.user_config,
- (void __user *)chan_config->config,
- sizeof(struct vpfe_rsz_config_params)))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * resizer_get_configuration() - get resizer config
- * @resizer: vpfe resizer device pointer.
- * @channel: image processor logical channel.
- * @chan_config: resizer channel configuration.
- */
-static int
-resizer_get_configuration(struct vpfe_resizer_device *resizer,
- struct vpfe_rsz_config *chan_config)
-{
- struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
-
- if (!chan_config->config) {
- dev_err(dev, "Resizer channel invalid pointer\n");
- return -EINVAL;
- }
-
- if (copy_to_user((void __user *)chan_config->config,
- (void *)&resizer->config.user_config,
- sizeof(struct vpfe_rsz_config_params))) {
- dev_err(dev, "resizer_get_configuration: Error in copy to user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
-/*
- * VPFE video operations
- */
-
-/*
- * resizer_a_video_out_queue() - RESIZER-A video out queue
- * @vpfe_dev: vpfe device pointer.
- * @addr: buffer address.
- */
-static int resizer_a_video_out_queue(struct vpfe_device *vpfe_dev,
- unsigned long addr)
-{
- struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
-
- return resizer_set_outaddr(resizer->base_addr,
- &resizer->config, RSZ_A, addr);
-}
-
-/*
- * resizer_b_video_out_queue() - RESIZER-B video out queue
- * @vpfe_dev: vpfe device pointer.
- * @addr: buffer address.
- */
-static int resizer_b_video_out_queue(struct vpfe_device *vpfe_dev,
- unsigned long addr)
-{
- struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
-
- return resizer_set_outaddr(resizer->base_addr,
- &resizer->config, RSZ_B, addr);
-}
-
-static const struct vpfe_video_operations resizer_a_video_ops = {
- .queue = resizer_a_video_out_queue,
-};
-
-static const struct vpfe_video_operations resizer_b_video_ops = {
- .queue = resizer_b_video_out_queue,
-};
-
-static void resizer_enable(struct vpfe_resizer_device *resizer, int en)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
- unsigned char val;
-
- if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE)
- return;
-
- if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF &&
- ipipeif_sink == IPIPEIF_INPUT_MEMORY) {
- do {
- val = regr_rsz(resizer->base_addr, RSZ_SRC_EN);
- } while (val);
-
- if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
- do {
- val = regr_rsz(resizer->base_addr, RSZ_A);
- } while (val);
- }
- if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
- do {
- val = regr_rsz(resizer->base_addr, RSZ_B);
- } while (val);
- }
- }
- if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
- rsz_enable(resizer->base_addr, RSZ_A, en);
-
- if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
- rsz_enable(resizer->base_addr, RSZ_B, en);
-}
-
-
-/*
- * resizer_ss_isr() - resizer module single-shot buffer scheduling isr
- * @resizer: vpfe resizer device pointer.
- */
-static void resizer_ss_isr(struct vpfe_resizer_device *resizer)
-{
- struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
- struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- struct vpfe_pipeline *pipe = &video_out->pipe;
- u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
- u32 val;
-
- if (ipipeif_sink != IPIPEIF_INPUT_MEMORY)
- return;
-
- if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) {
- val = vpss_dma_complete_interrupt();
- if (val != 0 && val != 2)
- return;
- }
-
- if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) {
- spin_lock(&video_out->dma_queue_lock);
- vpfe_video_process_buffer_complete(video_out);
- video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
- vpfe_video_schedule_next_buffer(video_out);
- spin_unlock(&video_out->dma_queue_lock);
- }
-
- /* If resizer B is enabled */
- if (pipe->output_num > 1 && resizer->resizer_b.output ==
- RESIZER_OUTPUT_MEMORY) {
- spin_lock(&video_out2->dma_queue_lock);
- vpfe_video_process_buffer_complete(video_out2);
- video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
- vpfe_video_schedule_next_buffer(video_out2);
- spin_unlock(&video_out2->dma_queue_lock);
- }
-
- /* start HW if buffers are queued */
- if (vpfe_video_is_pipe_ready(pipe) &&
- resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) {
- resizer_enable(resizer, 1);
- vpfe_ipipe_enable(vpfe_dev, 1);
- vpfe_ipipeif_enable(vpfe_dev);
- }
-}
-
-/*
- * vpfe_resizer_buffer_isr() - resizer module buffer scheduling isr
- * @resizer: vpfe resizer device pointer.
- */
-void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
- struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
- struct vpfe_pipeline *pipe = &resizer->resizer_a.video_out.pipe;
- enum v4l2_field field;
- int fid;
-
- if (!video_out->started)
- return;
-
- if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE)
- return;
-
- field = video_out->fmt.fmt.pix.field;
- if (field == V4L2_FIELD_NONE) {
- /* handle progressive frame capture */
- if (video_out->cur_frm != video_out->next_frm) {
- vpfe_video_process_buffer_complete(video_out);
- if (pipe->output_num > 1)
- vpfe_video_process_buffer_complete(video_out2);
- }
-
- video_out->skip_frame_count--;
- if (!video_out->skip_frame_count) {
- video_out->skip_frame_count =
- video_out->skip_frame_count_init;
- rsz_src_enable(resizer->base_addr, 1);
- } else {
- rsz_src_enable(resizer->base_addr, 0);
- }
- return;
- }
-
- /* handle interlaced frame capture */
- fid = vpfe_isif_get_fid(vpfe_dev);
-
- /* switch the software maintained field id */
- video_out->field_id ^= 1;
- if (fid == video_out->field_id) {
- /*
- * we are in-sync here,continue.
- * One frame is just being captured. If the
- * next frame is available, release the current
- * frame and move on
- */
- if (fid == 0 && video_out->cur_frm != video_out->next_frm) {
- vpfe_video_process_buffer_complete(video_out);
- if (pipe->output_num > 1)
- vpfe_video_process_buffer_complete(video_out2);
- }
- } else if (fid == 0) {
- /*
- * out of sync. Recover from any hardware out-of-sync.
- * May loose one frame
- */
- video_out->field_id = fid;
- }
-}
-
-/*
- * vpfe_resizer_dma_isr() - resizer module dma isr
- * @resizer: vpfe resizer device pointer.
- */
-void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer)
-{
- struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
- struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- struct vpfe_pipeline *pipe = &video_out->pipe;
- int schedule_capture = 0;
- enum v4l2_field field;
- int fid;
-
- if (!video_out->started)
- return;
-
- if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) {
- resizer_ss_isr(resizer);
- return;
- }
-
- field = video_out->fmt.fmt.pix.field;
- if (field == V4L2_FIELD_NONE) {
- if (!list_empty(&video_out->dma_queue) &&
- video_out->cur_frm == video_out->next_frm)
- schedule_capture = 1;
- } else {
- fid = vpfe_isif_get_fid(vpfe_dev);
- if (fid == video_out->field_id) {
- /* we are in-sync here,continue */
- if (fid == 1 && !list_empty(&video_out->dma_queue) &&
- video_out->cur_frm == video_out->next_frm)
- schedule_capture = 1;
- }
- }
-
- if (!schedule_capture)
- return;
-
- spin_lock(&video_out->dma_queue_lock);
- vpfe_video_schedule_next_buffer(video_out);
- spin_unlock(&video_out->dma_queue_lock);
- if (pipe->output_num > 1) {
- spin_lock(&video_out2->dma_queue_lock);
- vpfe_video_schedule_next_buffer(video_out2);
- spin_unlock(&video_out2->dma_queue_lock);
- }
-}
-
-/*
- * V4L2 subdev operations
- */
-
-/*
- * resizer_ioctl() - Handle resizer module private ioctl's
- * @sd: pointer to v4l2 subdev structure
- * @cmd: configuration command
- * @arg: configuration argument
- */
-static long resizer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
- struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
- struct vpfe_rsz_config *user_config;
- int ret = -ENOIOCTLCMD;
-
- if (&resizer->crop_resizer.subdev != sd)
- return ret;
-
- switch (cmd) {
- case VIDIOC_VPFE_RSZ_S_CONFIG:
- user_config = arg;
- ret = resizer_set_configuration(resizer, user_config);
- break;
-
- case VIDIOC_VPFE_RSZ_G_CONFIG:
- user_config = arg;
- if (!user_config->config) {
- dev_err(dev, "error in VIDIOC_VPFE_RSZ_G_CONFIG\n");
- return -EINVAL;
- }
- ret = resizer_get_configuration(resizer, user_config);
- break;
- }
- return ret;
-}
-
-static int resizer_do_hw_setup(struct vpfe_resizer_device *resizer)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
- u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
- struct resizer_params *param = &resizer->config;
- int ret = 0;
-
- if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY ||
- resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) {
- if (ipipeif_sink == IPIPEIF_INPUT_MEMORY &&
- ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
- ret = resizer_configure_in_single_shot_mode(resizer);
- else
- ret = resizer_configure_in_continuous_mode(resizer);
- if (ret)
- return ret;
- ret = config_rsz_hw(resizer, param);
- }
- return ret;
-}
-
-/*
- * resizer_set_stream() - Enable/Disable streaming on resizer subdev
- * @sd: pointer to v4l2 subdev structure
- * @enable: 1 == Enable, 0 == Disable
- */
-static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
-
- if (&resizer->crop_resizer.subdev != sd)
- return 0;
-
- if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY)
- return 0;
-
- switch (enable) {
- case 1:
- if (resizer_do_hw_setup(resizer) < 0)
- return -EINVAL;
- resizer_enable(resizer, enable);
- break;
-
- case 0:
- resizer_enable(resizer, enable);
- break;
- }
-
- return 0;
-}
-
-/*
- * __resizer_get_format() - helper function for getting resizer format
- * @sd: pointer to subdev.
- * @cfg: V4L2 subdev pad config
- * @pad: pad number.
- * @which: wanted subdev format.
- * Return wanted mbus frame format.
- */
-static struct v4l2_mbus_framefmt *
-__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
-
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(sd, cfg, pad);
- if (&resizer->crop_resizer.subdev == sd)
- return &resizer->crop_resizer.formats[pad];
- if (&resizer->resizer_a.subdev == sd)
- return &resizer->resizer_a.formats[pad];
- if (&resizer->resizer_b.subdev == sd)
- return &resizer->resizer_b.formats[pad];
- return NULL;
-}
-
-/*
- * resizer_try_format() - Handle try format by pad subdev method
- * @sd: pointer to subdev.
- * @cfg: V4L2 subdev pad config
- * @pad: pad num.
- * @fmt: pointer to v4l2 format structure.
- * @which: wanted subdev format.
- */
-static void
-resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- unsigned int pad, struct v4l2_mbus_framefmt *fmt,
- enum v4l2_subdev_format_whence which)
-{
- struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
- unsigned int max_out_height;
- unsigned int max_out_width;
- unsigned int i;
-
- if ((&resizer->resizer_a.subdev == sd && pad == RESIZER_PAD_SINK) ||
- (&resizer->resizer_b.subdev == sd && pad == RESIZER_PAD_SINK) ||
- (&resizer->crop_resizer.subdev == sd &&
- (pad == RESIZER_CROP_PAD_SOURCE ||
- pad == RESIZER_CROP_PAD_SOURCE2 || pad == RESIZER_CROP_PAD_SINK))) {
- for (i = 0; i < ARRAY_SIZE(resizer_input_formats); i++) {
- if (fmt->code == resizer_input_formats[i])
- break;
- }
- /* If not found, use UYVY as default */
- if (i >= ARRAY_SIZE(resizer_input_formats))
- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
-
- fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
- MAX_IN_WIDTH);
- fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
- MAX_IN_HEIGHT);
- } else if (&resizer->resizer_a.subdev == sd &&
- pad == RESIZER_PAD_SOURCE) {
- max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
- max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
-
- for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) {
- if (fmt->code == resizer_output_formats[i])
- break;
- }
- /* If not found, use UYVY as default */
- if (i >= ARRAY_SIZE(resizer_output_formats))
- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
-
- fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
- max_out_width);
- fmt->width &= ~15;
- fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
- max_out_height);
- } else if (&resizer->resizer_b.subdev == sd &&
- pad == RESIZER_PAD_SOURCE) {
- max_out_width = IPIPE_MAX_OUTPUT_WIDTH_B;
- max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_B;
-
- for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) {
- if (fmt->code == resizer_output_formats[i])
- break;
- }
- /* If not found, use UYVY as default */
- if (i >= ARRAY_SIZE(resizer_output_formats))
- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
-
- fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
- max_out_width);
- fmt->width &= ~15;
- fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
- max_out_height);
- }
-}
-
-/*
- * resizer_set_format() - Handle set format by pads subdev method
- * @sd: pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int resizer_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- resizer_try_format(sd, cfg, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- return 0;
-
- if (&resizer->crop_resizer.subdev == sd) {
- if (fmt->pad == RESIZER_CROP_PAD_SINK) {
- resizer->crop_resizer.formats[fmt->pad] = fmt->format;
- } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE &&
- resizer->crop_resizer.output == RESIZER_A) {
- resizer->crop_resizer.formats[fmt->pad] = fmt->format;
- resizer->crop_resizer.
- formats[RESIZER_CROP_PAD_SOURCE2] = fmt->format;
- } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE2 &&
- resizer->crop_resizer.output2 == RESIZER_B) {
- resizer->crop_resizer.formats[fmt->pad] = fmt->format;
- resizer->crop_resizer.
- formats[RESIZER_CROP_PAD_SOURCE] = fmt->format;
- } else {
- return -EINVAL;
- }
- } else if (&resizer->resizer_a.subdev == sd) {
- if (fmt->pad == RESIZER_PAD_SINK)
- resizer->resizer_a.formats[fmt->pad] = fmt->format;
- else if (fmt->pad == RESIZER_PAD_SOURCE)
- resizer->resizer_a.formats[fmt->pad] = fmt->format;
- else
- return -EINVAL;
- } else if (&resizer->resizer_b.subdev == sd) {
- if (fmt->pad == RESIZER_PAD_SINK)
- resizer->resizer_b.formats[fmt->pad] = fmt->format;
- else if (fmt->pad == RESIZER_PAD_SOURCE)
- resizer->resizer_b.formats[fmt->pad] = fmt->format;
- else
- return -EINVAL;
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * resizer_get_format() - Retrieve the video format on a pad
- * @sd: pointer to v4l2 subdev structure.
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int resizer_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
-{
- struct v4l2_mbus_framefmt *format;
-
- format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- fmt->format = *format;
-
- return 0;
-}
-
-/*
- * resizer_enum_frame_size() - enum frame sizes on pads
- * @sd: Pointer to subdevice.
- * @cfg: V4L2 subdev pad config
- * @code: pointer to v4l2_subdev_frame_size_enum structure.
- */
-static int resizer_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- struct v4l2_mbus_framefmt format;
-
- if (fse->index != 0)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = 1;
- format.height = 1;
- resizer_try_format(sd, cfg, fse->pad, &format, fse->which);
- fse->min_width = format.width;
- fse->min_height = format.height;
-
- if (format.code != fse->code)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = -1;
- format.height = -1;
- resizer_try_format(sd, cfg, fse->pad, &format, fse->which);
- fse->max_width = format.width;
- fse->max_height = format.height;
-
- return 0;
-}
-
-/*
- * resizer_enum_mbus_code() - enum mbus codes for pads
- * @sd: Pointer to subdevice.
- * @cfg: V4L2 subdev pad config
- * @code: pointer to v4l2_subdev_mbus_code_enum structure
- */
-static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->pad == RESIZER_PAD_SINK) {
- if (code->index >= ARRAY_SIZE(resizer_input_formats))
- return -EINVAL;
-
- code->code = resizer_input_formats[code->index];
- } else if (code->pad == RESIZER_PAD_SOURCE) {
- if (code->index >= ARRAY_SIZE(resizer_output_formats))
- return -EINVAL;
-
- code->code = resizer_output_formats[code->index];
- }
-
- return 0;
-}
-
-/*
- * resizer_init_formats() - Initialize formats on all pads
- * @sd: Pointer to subdevice.
- * @fh: V4L2 subdev file handle.
- *
- * Initialize all pad formats with default values. Try formats are
- * initialized on the file handle.
- */
-static int resizer_init_formats(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh)
-{
- __u32 which = V4L2_SUBDEV_FORMAT_TRY;
- struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
- struct v4l2_subdev_format format;
-
- if (&resizer->crop_resizer.subdev == sd) {
- memset(&format, 0, sizeof(format));
- format.pad = RESIZER_CROP_PAD_SINK;
- format.which = which;
- format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
- format.format.width = MAX_IN_WIDTH;
- format.format.height = MAX_IN_HEIGHT;
- resizer_set_format(sd, fh->pad, &format);
-
- memset(&format, 0, sizeof(format));
- format.pad = RESIZER_CROP_PAD_SOURCE;
- format.which = which;
- format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
- format.format.width = MAX_IN_WIDTH;
- format.format.height = MAX_IN_WIDTH;
- resizer_set_format(sd, fh->pad, &format);
-
- memset(&format, 0, sizeof(format));
- format.pad = RESIZER_CROP_PAD_SOURCE2;
- format.which = which;
- format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
- format.format.width = MAX_IN_WIDTH;
- format.format.height = MAX_IN_WIDTH;
- resizer_set_format(sd, fh->pad, &format);
- } else if (&resizer->resizer_a.subdev == sd) {
- memset(&format, 0, sizeof(format));
- format.pad = RESIZER_PAD_SINK;
- format.which = which;
- format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
- format.format.width = MAX_IN_WIDTH;
- format.format.height = MAX_IN_HEIGHT;
- resizer_set_format(sd, fh->pad, &format);
-
- memset(&format, 0, sizeof(format));
- format.pad = RESIZER_PAD_SOURCE;
- format.which = which;
- format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
- format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
- format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
- resizer_set_format(sd, fh->pad, &format);
- } else if (&resizer->resizer_b.subdev == sd) {
- memset(&format, 0, sizeof(format));
- format.pad = RESIZER_PAD_SINK;
- format.which = which;
- format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
- format.format.width = MAX_IN_WIDTH;
- format.format.height = MAX_IN_HEIGHT;
- resizer_set_format(sd, fh->pad, &format);
-
- memset(&format, 0, sizeof(format));
- format.pad = RESIZER_PAD_SOURCE;
- format.which = which;
- format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
- format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B;
- format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B;
- resizer_set_format(sd, fh->pad, &format);
- }
-
- return 0;
-}
-
-/* subdev core operations */
-static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = {
- .ioctl = resizer_ioctl,
-};
-
-/* subdev internal operations */
-static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
- .open = resizer_init_formats,
-};
-
-/* subdev video operations */
-static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
- .s_stream = resizer_set_stream,
-};
-
-/* subdev pad operations */
-static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
- .enum_mbus_code = resizer_enum_mbus_code,
- .enum_frame_size = resizer_enum_frame_size,
- .get_fmt = resizer_get_format,
- .set_fmt = resizer_set_format,
-};
-
-/* subdev operations */
-static const struct v4l2_subdev_ops resizer_v4l2_ops = {
- .core = &resizer_v4l2_core_ops,
- .video = &resizer_v4l2_video_ops,
- .pad = &resizer_v4l2_pad_ops,
-};
-
-/*
- * Media entity operations
- */
-
-/*
- * resizer_link_setup() - Setup resizer connections
- * @entity: Pointer to media entity structure
- * @local: Pointer to local pad array
- * @remote: Pointer to remote pad array
- * @flags: Link flags
- * return -EINVAL or zero on success
- */
-static int resizer_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
- u16 ipipe_source = vpfe_dev->vpfe_ipipe.output;
- unsigned int index = local->index;
-
- /* FIXME: this is actually a hack! */
- if (is_media_entity_v4l2_subdev(remote->entity))
- index |= 2 << 16;
-
- if (&resizer->crop_resizer.subdev == sd) {
- switch (index) {
- case RESIZER_CROP_PAD_SINK | 2 << 16:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- resizer->crop_resizer.input =
- RESIZER_CROP_INPUT_NONE;
- break;
- }
-
- if (resizer->crop_resizer.input !=
- RESIZER_CROP_INPUT_NONE)
- return -EBUSY;
- if (ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
- resizer->crop_resizer.input =
- RESIZER_CROP_INPUT_IPIPEIF;
- else if (ipipe_source == IPIPE_OUTPUT_RESIZER)
- resizer->crop_resizer.input =
- RESIZER_CROP_INPUT_IPIPE;
- else
- return -EINVAL;
- break;
-
- case RESIZER_CROP_PAD_SOURCE | 2 << 16:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- resizer->crop_resizer.output =
- RESIZER_CROP_OUTPUT_NONE;
- break;
- }
- if (resizer->crop_resizer.output !=
- RESIZER_CROP_OUTPUT_NONE)
- return -EBUSY;
- resizer->crop_resizer.output = RESIZER_A;
- break;
-
- case RESIZER_CROP_PAD_SOURCE2 | 2 << 16:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- resizer->crop_resizer.output2 =
- RESIZER_CROP_OUTPUT_NONE;
- break;
- }
- if (resizer->crop_resizer.output2 !=
- RESIZER_CROP_OUTPUT_NONE)
- return -EBUSY;
- resizer->crop_resizer.output2 = RESIZER_B;
- break;
-
- default:
- return -EINVAL;
- }
- } else if (&resizer->resizer_a.subdev == sd) {
- switch (index) {
- case RESIZER_PAD_SINK | 2 << 16:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- resizer->resizer_a.input = RESIZER_INPUT_NONE;
- break;
- }
- if (resizer->resizer_a.input != RESIZER_INPUT_NONE)
- return -EBUSY;
- resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER;
- break;
-
- case RESIZER_PAD_SOURCE:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- resizer->resizer_a.output = RESIZER_OUTPUT_NONE;
- break;
- }
- if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
- return -EBUSY;
- resizer->resizer_a.output = RESIZER_OUTPUT_MEMORY;
- break;
-
- default:
- return -EINVAL;
- }
- } else if (&resizer->resizer_b.subdev == sd) {
- switch (index) {
- case RESIZER_PAD_SINK | 2 << 16:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- resizer->resizer_b.input = RESIZER_INPUT_NONE;
- break;
- }
- if (resizer->resizer_b.input != RESIZER_INPUT_NONE)
- return -EBUSY;
- resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER;
- break;
-
- case RESIZER_PAD_SOURCE:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- resizer->resizer_b.output = RESIZER_OUTPUT_NONE;
- break;
- }
- if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
- return -EBUSY;
- resizer->resizer_b.output = RESIZER_OUTPUT_MEMORY;
- break;
-
- default:
- return -EINVAL;
- }
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const struct media_entity_operations resizer_media_ops = {
- .link_setup = resizer_link_setup,
-};
-
-/*
- * vpfe_resizer_unregister_entities() - Unregister entity
- * @vpfe_rsz - pointer to resizer subdevice structure.
- */
-void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz)
-{
- /* unregister video devices */
- vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out);
- vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out);
-
- /* unregister subdev */
- v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev);
- v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev);
- v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev);
- /* cleanup entity */
- media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
- media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
- media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
-}
-
-/*
- * vpfe_resizer_register_entities() - Register entity
- * @resizer - pointer to resizer device.
- * @vdev: pointer to v4l2 device structure.
- */
-int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer,
- struct v4l2_device *vdev)
-{
- struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
- unsigned int flags = 0;
- int ret;
-
- /* Register the crop resizer subdev */
- ret = v4l2_device_register_subdev(vdev, &resizer->crop_resizer.subdev);
- if (ret < 0) {
- pr_err("Failed to register crop resizer as v4l2-subdev\n");
- return ret;
- }
- /* Register Resizer-A subdev */
- ret = v4l2_device_register_subdev(vdev, &resizer->resizer_a.subdev);
- if (ret < 0) {
- pr_err("Failed to register resizer-a as v4l2-subdev\n");
- return ret;
- }
- /* Register Resizer-B subdev */
- ret = v4l2_device_register_subdev(vdev, &resizer->resizer_b.subdev);
- if (ret < 0) {
- pr_err("Failed to register resizer-b as v4l2-subdev\n");
- return ret;
- }
- /* Register video-out device for resizer-a */
- ret = vpfe_video_register(&resizer->resizer_a.video_out, vdev);
- if (ret) {
- pr_err("Failed to register RSZ-A video-out device\n");
- goto out_video_out2_register;
- }
- resizer->resizer_a.video_out.vpfe_dev = vpfe_dev;
-
- /* Register video-out device for resizer-b */
- ret = vpfe_video_register(&resizer->resizer_b.video_out, vdev);
- if (ret) {
- pr_err("Failed to register RSZ-B video-out device\n");
- goto out_video_out2_register;
- }
- resizer->resizer_b.video_out.vpfe_dev = vpfe_dev;
-
- /* create link between Resizer Crop----> Resizer A*/
- ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 1,
- &resizer->resizer_a.subdev.entity,
- 0, flags);
- if (ret < 0)
- goto out_create_link;
-
- /* create link between Resizer Crop----> Resizer B*/
- ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 2,
- &resizer->resizer_b.subdev.entity,
- 0, flags);
- if (ret < 0)
- goto out_create_link;
-
- /* create link between Resizer A ----> video out */
- ret = media_create_pad_link(&resizer->resizer_a.subdev.entity, 1,
- &resizer->resizer_a.video_out.video_dev.entity, 0, flags);
- if (ret < 0)
- goto out_create_link;
-
- /* create link between Resizer B ----> video out */
- ret = media_create_pad_link(&resizer->resizer_b.subdev.entity, 1,
- &resizer->resizer_b.video_out.video_dev.entity, 0, flags);
- if (ret < 0)
- goto out_create_link;
-
- return 0;
-
-out_create_link:
- vpfe_video_unregister(&resizer->resizer_b.video_out);
-out_video_out2_register:
- vpfe_video_unregister(&resizer->resizer_a.video_out);
- v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev);
- v4l2_device_unregister_subdev(&resizer->resizer_a.subdev);
- v4l2_device_unregister_subdev(&resizer->resizer_b.subdev);
- media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
- media_entity_cleanup(&resizer->resizer_a.subdev.entity);
- media_entity_cleanup(&resizer->resizer_b.subdev.entity);
- return ret;
-}
-
-/*
- * vpfe_resizer_init() - resizer device initialization.
- * @vpfe_rsz - pointer to resizer device
- * @pdev: platform device pointer.
- */
-int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
- struct platform_device *pdev)
-{
- struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev;
- struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0];
- struct media_entity *me = &sd->entity;
- resource_size_t res_len;
- struct resource *res;
- int ret;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
- if (!res)
- return -ENOENT;
-
- res_len = resource_size(res);
- res = request_mem_region(res->start, res_len, res->name);
- if (!res)
- return -EBUSY;
-
- vpfe_rsz->base_addr = ioremap_nocache(res->start, res_len);
- if (!vpfe_rsz->base_addr)
- return -EBUSY;
-
- v4l2_subdev_init(sd, &resizer_v4l2_ops);
- sd->internal_ops = &resizer_v4l2_internal_ops;
- strscpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
- v4l2_set_subdevdata(sd, vpfe_rsz);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- pads[RESIZER_CROP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[RESIZER_CROP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- pads[RESIZER_CROP_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE;
-
- vpfe_rsz->crop_resizer.input = RESIZER_CROP_INPUT_NONE;
- vpfe_rsz->crop_resizer.output = RESIZER_CROP_OUTPUT_NONE;
- vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE;
- vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz;
- me->ops = &resizer_media_ops;
- ret = media_entity_pads_init(me, RESIZER_CROP_PADS_NUM, pads);
- if (ret)
- return ret;
-
- sd = &vpfe_rsz->resizer_a.subdev;
- pads = &vpfe_rsz->resizer_a.pads[0];
- me = &sd->entity;
-
- v4l2_subdev_init(sd, &resizer_v4l2_ops);
- sd->internal_ops = &resizer_v4l2_internal_ops;
- strscpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
- v4l2_set_subdevdata(sd, vpfe_rsz);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-
- vpfe_rsz->resizer_a.input = RESIZER_INPUT_NONE;
- vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE;
- vpfe_rsz->resizer_a.rsz_device = vpfe_rsz;
- me->ops = &resizer_media_ops;
- ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads);
- if (ret)
- return ret;
-
- sd = &vpfe_rsz->resizer_b.subdev;
- pads = &vpfe_rsz->resizer_b.pads[0];
- me = &sd->entity;
-
- v4l2_subdev_init(sd, &resizer_v4l2_ops);
- sd->internal_ops = &resizer_v4l2_internal_ops;
- strscpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
- v4l2_set_subdevdata(sd, vpfe_rsz);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-
- vpfe_rsz->resizer_b.input = RESIZER_INPUT_NONE;
- vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE;
- vpfe_rsz->resizer_b.rsz_device = vpfe_rsz;
- me->ops = &resizer_media_ops;
- ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads);
- if (ret)
- return ret;
-
- vpfe_rsz->resizer_a.video_out.ops = &resizer_a_video_ops;
- vpfe_rsz->resizer_a.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ret = vpfe_video_init(&vpfe_rsz->resizer_a.video_out, "RSZ-A");
- if (ret) {
- pr_err("Failed to init RSZ video-out device\n");
- return ret;
- }
- vpfe_rsz->resizer_b.video_out.ops = &resizer_b_video_ops;
- vpfe_rsz->resizer_b.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ret = vpfe_video_init(&vpfe_rsz->resizer_b.video_out, "RSZ-B");
- if (ret) {
- pr_err("Failed to init RSZ video-out2 device\n");
- return ret;
- }
- memset(&vpfe_rsz->config, 0, sizeof(struct resizer_params));
-
- return 0;
-}
-
-void
-vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz,
- struct platform_device *pdev)
-{
- struct resource *res;
-
- iounmap(vpfe_rsz->base_addr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
- if (res)
- release_mem_region(res->start,
- resource_size(res));
-}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.h b/drivers/staging/media/davinci_vpfe/dm365_resizer.h
deleted file mode 100644
index 5e31de96b2c9..000000000000
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_DM365_RESIZER_H
-#define _DAVINCI_VPFE_DM365_RESIZER_H
-
-enum resizer_oper_mode {
- RESIZER_MODE_CONTINUOUS = 0,
- RESIZER_MODE_ONE_SHOT = 1,
-};
-
-struct f_div_pass {
- unsigned int o_hsz;
- unsigned int i_hps;
- unsigned int h_phs;
- unsigned int src_hps;
- unsigned int src_hsz;
-};
-
-#define MAX_PASSES 2
-
-struct f_div_param {
- unsigned char en;
- unsigned int num_passes;
- struct f_div_pass pass[MAX_PASSES];
-};
-
-/* Resizer Rescale Parameters*/
-struct resizer_scale_param {
- bool h_flip;
- bool v_flip;
- bool cen;
- bool yen;
- unsigned short i_vps;
- unsigned short i_hps;
- unsigned short o_vsz;
- unsigned short o_hsz;
- unsigned short v_phs_y;
- unsigned short v_phs_c;
- unsigned short v_dif;
- /* resize method - Luminance */
- enum vpfe_rsz_intp_t v_typ_y;
- /* resize method - Chrominance */
- enum vpfe_rsz_intp_t v_typ_c;
- /* vertical lpf intensity - Luminance */
- unsigned char v_lpf_int_y;
- /* vertical lpf intensity - Chrominance */
- unsigned char v_lpf_int_c;
- unsigned short h_phs;
- unsigned short h_dif;
- /* resize method - Luminance */
- enum vpfe_rsz_intp_t h_typ_y;
- /* resize method - Chrominance */
- enum vpfe_rsz_intp_t h_typ_c;
- /* horizontal lpf intensity - Luminance */
- unsigned char h_lpf_int_y;
- /* horizontal lpf intensity - Chrominance */
- unsigned char h_lpf_int_c;
- bool dscale_en;
- enum vpfe_rsz_down_scale_ave_sz h_dscale_ave_sz;
- enum vpfe_rsz_down_scale_ave_sz v_dscale_ave_sz;
- /* store the calculated frame division parameter */
- struct f_div_param f_div;
-};
-
-enum resizer_rgb_t {
- OUTPUT_32BIT,
- OUTPUT_16BIT
-};
-
-enum resizer_rgb_msk_t {
- NOMASK = 0,
- MASKLAST2 = 1,
-};
-
-/* Resizer RGB Conversion Parameters */
-struct resizer_rgb {
- bool rgb_en;
- enum resizer_rgb_t rgb_typ;
- enum resizer_rgb_msk_t rgb_msk0;
- enum resizer_rgb_msk_t rgb_msk1;
- unsigned int rgb_alpha_val;
-};
-
-/* Resizer External Memory Parameters */
-struct rsz_ext_mem_param {
- unsigned int rsz_sdr_oft_y;
- unsigned int rsz_sdr_ptr_s_y;
- unsigned int rsz_sdr_ptr_e_y;
- unsigned int rsz_sdr_oft_c;
- unsigned int rsz_sdr_ptr_s_c;
- unsigned int rsz_sdr_ptr_e_c;
- /* offset to be added to buffer start when flipping for y/ycbcr */
- unsigned int flip_ofst_y;
- /* offset to be added to buffer start when flipping for c */
- unsigned int flip_ofst_c;
- /* c offset for YUV 420SP */
- unsigned int c_offset;
- /* User Defined Y offset for YUV 420SP or YUV420ILE data */
- unsigned int user_y_ofst;
- /* User Defined C offset for YUV 420SP data */
- unsigned int user_c_ofst;
-};
-
-enum rsz_data_source {
- IPIPE_DATA,
- IPIPEIF_DATA
-};
-
-enum rsz_src_img_fmt {
- RSZ_IMG_422,
- RSZ_IMG_420
-};
-
-enum rsz_dpaths_bypass_t {
- BYPASS_OFF = 0,
- BYPASS_ON = 1,
-};
-
-struct rsz_common_params {
- unsigned int vps;
- unsigned int vsz;
- unsigned int hps;
- unsigned int hsz;
- /* 420 or 422 */
- enum rsz_src_img_fmt src_img_fmt;
- /* Y or C when src_fmt is 420, 0 - y, 1 - c */
- unsigned char y_c;
- /* flip raw or ycbcr */
- unsigned char raw_flip;
- /* IPIPE or IPIPEIF data */
- enum rsz_data_source source;
- enum rsz_dpaths_bypass_t passthrough;
- unsigned char yuv_y_min;
- unsigned char yuv_y_max;
- unsigned char yuv_c_min;
- unsigned char yuv_c_max;
- bool rsz_seq_crv;
- enum vpfe_chr_pos out_chr_pos;
-};
-
-struct resizer_params {
- enum resizer_oper_mode oper_mode;
- struct rsz_common_params rsz_common;
- struct resizer_scale_param rsz_rsc_param[2];
- struct resizer_rgb rsz2rgb[2];
- struct rsz_ext_mem_param ext_mem_param[2];
- bool rsz_en[2];
- struct vpfe_rsz_config_params user_config;
-};
-
-#define ENABLE 1
-#define DISABLE (!ENABLE)
-
-#define RESIZER_CROP_PAD_SINK 0
-#define RESIZER_CROP_PAD_SOURCE 1
-#define RESIZER_CROP_PAD_SOURCE2 2
-
-#define RESIZER_CROP_PADS_NUM 3
-
-enum resizer_crop_input_entity {
- RESIZER_CROP_INPUT_NONE = 0,
- RESIZER_CROP_INPUT_IPIPEIF = 1,
- RESIZER_CROP_INPUT_IPIPE = 2,
-};
-
-enum resizer_crop_output_entity {
- RESIZER_CROP_OUTPUT_NONE,
- RESIZER_A,
- RESIZER_B,
-};
-
-struct dm365_crop_resizer_device {
- struct v4l2_subdev subdev;
- struct media_pad pads[RESIZER_CROP_PADS_NUM];
- struct v4l2_mbus_framefmt formats[RESIZER_CROP_PADS_NUM];
- enum resizer_crop_input_entity input;
- enum resizer_crop_output_entity output;
- enum resizer_crop_output_entity output2;
- struct vpfe_resizer_device *rsz_device;
-};
-
-#define RESIZER_PAD_SINK 0
-#define RESIZER_PAD_SOURCE 1
-
-#define RESIZER_PADS_NUM 2
-
-enum resizer_input_entity {
- RESIZER_INPUT_NONE = 0,
- RESIZER_INPUT_CROP_RESIZER = 1,
-};
-
-enum resizer_output_entity {
- RESIZER_OUTPUT_NONE = 0,
- RESIZER_OUTPUT_MEMORY = 1,
-};
-
-struct dm365_resizer_device {
- struct v4l2_subdev subdev;
- struct media_pad pads[RESIZER_PADS_NUM];
- struct v4l2_mbus_framefmt formats[RESIZER_PADS_NUM];
- enum resizer_input_entity input;
- enum resizer_output_entity output;
- struct vpfe_video_device video_out;
- struct vpfe_resizer_device *rsz_device;
-};
-
-struct vpfe_resizer_device {
- struct dm365_crop_resizer_device crop_resizer;
- struct dm365_resizer_device resizer_a;
- struct dm365_resizer_device resizer_b;
- struct resizer_params config;
- void __iomem *base_addr;
-};
-
-int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
- struct platform_device *pdev);
-int vpfe_resizer_register_entities(struct vpfe_resizer_device *vpfe_rsz,
- struct v4l2_device *v4l2_dev);
-void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz);
-void vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz,
- struct platform_device *pdev);
-void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer);
-void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer);
-
-#endif /* _DAVINCI_VPFE_DM365_RESIZER_H */
diff --git a/drivers/staging/media/davinci_vpfe/vpfe.h b/drivers/staging/media/davinci_vpfe/vpfe.h
deleted file mode 100644
index 1f8e011fc162..000000000000
--- a/drivers/staging/media/davinci_vpfe/vpfe.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _VPFE_H
-#define _VPFE_H
-
-#ifdef __KERNEL__
-#include <linux/v4l2-subdev.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
-
-#include <media/davinci/vpfe_types.h>
-
-#define CAPTURE_DRV_NAME "vpfe-capture"
-
-struct vpfe_route {
- __u32 input;
- __u32 output;
-};
-
-enum vpfe_subdev_id {
- VPFE_SUBDEV_TVP5146 = 1,
- VPFE_SUBDEV_MT9T031 = 2,
- VPFE_SUBDEV_TVP7002 = 3,
- VPFE_SUBDEV_MT9P031 = 4,
-};
-
-struct vpfe_ext_subdev_info {
- /* v4l2 subdev */
- struct v4l2_subdev *subdev;
- /* Sub device module name */
- char module_name[32];
- /* Sub device group id */
- int grp_id;
- /* Number of inputs supported */
- int num_inputs;
- /* inputs available at the sub device */
- struct v4l2_input *inputs;
- /* Sub dev routing information for each input */
- struct vpfe_route *routes;
- /* ccdc bus/interface configuration */
- struct vpfe_hw_if_param ccdc_if_params;
- /* i2c subdevice board info */
- struct i2c_board_info board_info;
- /* Is this a camera sub device ? */
- unsigned is_camera:1;
- /* check if sub dev supports routing */
- unsigned can_route:1;
- /* registered ? */
- unsigned registered:1;
-};
-
-struct vpfe_config {
- /* Number of sub devices connected to vpfe */
- int num_subdevs;
- /* information about each subdev */
- struct vpfe_ext_subdev_info *sub_devs;
- /* evm card info */
- char *card_name;
- /* setup function for the input path */
- int (*setup_input)(enum vpfe_subdev_id id);
- /* number of clocks */
- int num_clocks;
- /* clocks used for vpfe capture */
- char *clocks[];
-};
-#endif
-#endif
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
deleted file mode 100644
index 9dc28ffe38d5..000000000000
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
+++ /dev/null
@@ -1,716 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- *
- *
- * Driver name : VPFE Capture driver
- * VPFE Capture driver allows applications to capture and stream video
- * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as
- * TVP5146 or Raw Bayer RGB image data from an image sensor
- * such as Microns' MT9T001, MT9T031 etc.
- *
- * These SoCs have, in common, a Video Processing Subsystem (VPSS) that
- * consists of a Video Processing Front End (VPFE) for capturing
- * video/raw image data and Video Processing Back End (VPBE) for displaying
- * YUV data through an in-built analog encoder or Digital LCD port. This
- * driver is for capture through VPFE. A typical EVM using these SoCs have
- * following high level configuration.
- *
- * decoder(TVP5146/ YUV/
- * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF)
- * data input | |
- * V |
- * SDRAM |
- * V
- * Image Processor
- * |
- * V
- * SDRAM
- * The data flow happens from a decoder connected to the VPFE over a
- * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface
- * and to the input of VPFE through an optional MUX (if more inputs are
- * to be interfaced on the EVM). The input data is first passed through
- * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC
- * does very little or no processing on YUV data and does pre-process Raw
- * Bayer RGB data through modules such as Defect Pixel Correction (DFC)
- * Color Space Conversion (CSC), data gain/offset etc. After this, data
- * can be written to SDRAM or can be connected to the image processing
- * block such as IPIPE (on DM355/DM365 only).
- *
- * Features supported
- * - MMAP IO
- * - USERPTR IO
- * - Capture using TVP5146 over BT.656
- * - Support for interfacing decoders using sub device model
- * - Work with DM365 or DM355 or DM6446 CCDC to do Raw Bayer
- * RGB/YUV data capture to SDRAM.
- * - Chaining of Image Processor
- * - SINGLE-SHOT mode
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include "vpfe.h"
-#include "vpfe_mc_capture.h"
-
-static bool debug;
-static bool interface;
-
-module_param(interface, bool, 0444);
-module_param(debug, bool, 0644);
-
-/*
- * VPFE capture can be used for capturing video such as from TVP5146 or TVP7002
- * and for capture raw bayer data from camera sensors such as mt9p031. At this
- * point there is problem in co-existence of mt9p031 and tvp5146 due to i2c
- * address collision. So set the variable below from bootargs to do either video
- * capture or camera capture.
- * interface = 0 - video capture (from TVP514x or such),
- * interface = 1 - Camera capture (from mt9p031 or such)
- * Re-visit this when we fix the co-existence issue
- */
-MODULE_PARM_DESC(interface, "interface 0-1 (default:0)");
-MODULE_PARM_DESC(debug, "Debug level 0-1");
-
-MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Texas Instruments");
-
-/* map mbus_fmt to pixelformat */
-void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus,
- struct v4l2_pix_format *pix)
-{
- switch (mbus->code) {
- case MEDIA_BUS_FMT_UYVY8_2X8:
- pix->pixelformat = V4L2_PIX_FMT_UYVY;
- pix->bytesperline = pix->width * 2;
- break;
-
- case MEDIA_BUS_FMT_YUYV8_2X8:
- pix->pixelformat = V4L2_PIX_FMT_YUYV;
- pix->bytesperline = pix->width * 2;
- break;
-
- case MEDIA_BUS_FMT_YUYV10_1X20:
- pix->pixelformat = V4L2_PIX_FMT_UYVY;
- pix->bytesperline = pix->width * 2;
- break;
-
- case MEDIA_BUS_FMT_SGRBG12_1X12:
- pix->pixelformat = V4L2_PIX_FMT_SBGGR16;
- pix->bytesperline = pix->width * 2;
- break;
-
- case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
- pix->pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8;
- pix->bytesperline = pix->width;
- break;
-
- case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
- pix->pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8;
- pix->bytesperline = pix->width;
- break;
-
- case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
- pix->pixelformat = V4L2_PIX_FMT_NV12;
- pix->bytesperline = pix->width;
- break;
-
- case MEDIA_BUS_FMT_Y8_1X8:
- pix->pixelformat = V4L2_PIX_FMT_GREY;
- pix->bytesperline = pix->width;
- break;
-
- case MEDIA_BUS_FMT_UV8_1X8:
- pix->pixelformat = V4L2_PIX_FMT_UV8;
- pix->bytesperline = pix->width;
- break;
-
- default:
- pr_err("Invalid mbus code set\n");
- }
- /* pitch should be 32 bytes aligned */
- pix->bytesperline = ALIGN(pix->bytesperline, 32);
- if (pix->pixelformat == V4L2_PIX_FMT_NV12)
- pix->sizeimage = pix->bytesperline * pix->height +
- ((pix->bytesperline * pix->height) >> 1);
- else
- pix->sizeimage = pix->bytesperline * pix->height;
-}
-
-/* ISR for VINT0*/
-static irqreturn_t vpfe_isr(int irq, void *dev_id)
-{
- struct vpfe_device *vpfe_dev = dev_id;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__);
- vpfe_isif_buffer_isr(&vpfe_dev->vpfe_isif);
- vpfe_resizer_buffer_isr(&vpfe_dev->vpfe_resizer);
- return IRQ_HANDLED;
-}
-
-/* vpfe_vdint1_isr() - isr handler for VINT1 interrupt */
-static irqreturn_t vpfe_vdint1_isr(int irq, void *dev_id)
-{
- struct vpfe_device *vpfe_dev = dev_id;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__);
- vpfe_isif_vidint1_isr(&vpfe_dev->vpfe_isif);
- return IRQ_HANDLED;
-}
-
-/* vpfe_imp_dma_isr() - ISR for ipipe dma completion */
-static irqreturn_t vpfe_imp_dma_isr(int irq, void *dev_id)
-{
- struct vpfe_device *vpfe_dev = dev_id;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__);
- vpfe_ipipeif_ss_buffer_isr(&vpfe_dev->vpfe_ipipeif);
- vpfe_resizer_dma_isr(&vpfe_dev->vpfe_resizer);
- return IRQ_HANDLED;
-}
-
-/*
- * vpfe_disable_clock() - Disable clocks for vpfe capture driver
- * @vpfe_dev - ptr to vpfe capture device
- *
- * Disables clocks defined in vpfe configuration. The function
- * assumes that at least one clock is to be defined which is
- * true as of now.
- */
-static void vpfe_disable_clock(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
- int i;
-
- for (i = 0; i < vpfe_cfg->num_clocks; i++) {
- clk_disable_unprepare(vpfe_dev->clks[i]);
- clk_put(vpfe_dev->clks[i]);
- }
- kzfree(vpfe_dev->clks);
- v4l2_info(vpfe_dev->pdev->driver, "vpfe capture clocks disabled\n");
-}
-
-/*
- * vpfe_enable_clock() - Enable clocks for vpfe capture driver
- * @vpfe_dev - ptr to vpfe capture device
- *
- * Enables clocks defined in vpfe configuration. The function
- * assumes that at least one clock is to be defined which is
- * true as of now.
- */
-static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
- int ret = -EFAULT;
- int i;
-
- if (!vpfe_cfg->num_clocks)
- return 0;
-
- vpfe_dev->clks = kcalloc(vpfe_cfg->num_clocks,
- sizeof(*vpfe_dev->clks), GFP_KERNEL);
- if (!vpfe_dev->clks)
- return -ENOMEM;
-
- for (i = 0; i < vpfe_cfg->num_clocks; i++) {
- if (vpfe_cfg->clocks[i] == NULL) {
- v4l2_err(vpfe_dev->pdev->driver,
- "clock %s is not defined in vpfe config\n",
- vpfe_cfg->clocks[i]);
- goto out;
- }
-
- vpfe_dev->clks[i] =
- clk_get(vpfe_dev->pdev, vpfe_cfg->clocks[i]);
- if (IS_ERR(vpfe_dev->clks[i])) {
- v4l2_err(vpfe_dev->pdev->driver,
- "Failed to get clock %s\n",
- vpfe_cfg->clocks[i]);
- goto out;
- }
-
- if (clk_prepare_enable(vpfe_dev->clks[i])) {
- v4l2_err(vpfe_dev->pdev->driver,
- "vpfe clock %s not enabled\n",
- vpfe_cfg->clocks[i]);
- goto out;
- }
-
- v4l2_info(vpfe_dev->pdev->driver, "vpss clock %s enabled",
- vpfe_cfg->clocks[i]);
- }
-
- return 0;
-out:
- for (i = 0; i < vpfe_cfg->num_clocks; i++)
- if (!IS_ERR(vpfe_dev->clks[i])) {
- clk_disable_unprepare(vpfe_dev->clks[i]);
- clk_put(vpfe_dev->clks[i]);
- }
-
- v4l2_err(vpfe_dev->pdev->driver, "Failed to enable clocks\n");
- kzfree(vpfe_dev->clks);
-
- return ret;
-}
-
-/*
- * vpfe_detach_irq() - Detach IRQs for vpfe capture driver
- * @vpfe_dev - ptr to vpfe capture device
- *
- * Detach all IRQs defined in vpfe configuration.
- */
-static void vpfe_detach_irq(struct vpfe_device *vpfe_dev)
-{
- free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
- free_irq(vpfe_dev->ccdc_irq1, vpfe_dev);
- free_irq(vpfe_dev->imp_dma_irq, vpfe_dev);
-}
-
-/*
- * vpfe_attach_irq() - Attach IRQs for vpfe capture driver
- * @vpfe_dev - ptr to vpfe capture device
- *
- * Attach all IRQs defined in vpfe configuration.
- */
-static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
-{
- int ret;
-
- ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, 0,
- "vpfe_capture0", vpfe_dev);
- if (ret < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Error: requesting VINT0 interrupt\n");
- return ret;
- }
-
- ret = request_irq(vpfe_dev->ccdc_irq1, vpfe_vdint1_isr, 0,
- "vpfe_capture1", vpfe_dev);
- if (ret < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Error: requesting VINT1 interrupt\n");
- free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
- return ret;
- }
-
- ret = request_irq(vpfe_dev->imp_dma_irq, vpfe_imp_dma_isr,
- 0, "Imp_Sdram_Irq", vpfe_dev);
- if (ret < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Error: requesting IMP IRQ interrupt\n");
- free_irq(vpfe_dev->ccdc_irq1, vpfe_dev);
- free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
- return ret;
- }
-
- return 0;
-}
-
-/*
- * register_i2c_devices() - register all i2c v4l2 subdevs
- * @vpfe_dev - ptr to vpfe capture device
- *
- * register all i2c v4l2 subdevs
- */
-static int register_i2c_devices(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_ext_subdev_info *sdinfo;
- struct vpfe_config *vpfe_cfg;
- struct i2c_adapter *i2c_adap;
- unsigned int num_subdevs;
- int ret;
- int i;
- int k;
-
- vpfe_cfg = vpfe_dev->cfg;
- i2c_adap = i2c_get_adapter(1);
- num_subdevs = vpfe_cfg->num_subdevs;
- vpfe_dev->sd =
- kcalloc(num_subdevs, sizeof(struct v4l2_subdev *),
- GFP_KERNEL);
- if (!vpfe_dev->sd)
- return -ENOMEM;
-
- for (i = 0, k = 0; i < num_subdevs; i++) {
- sdinfo = &vpfe_cfg->sub_devs[i];
- /*
- * register subdevices based on interface setting. Currently
- * tvp5146 and mt9p031 cannot co-exists due to i2c address
- * conflicts. So only one of them is registered. Re-visit this
- * once we have support for i2c switch handling in i2c driver
- * framework
- */
- if (interface == sdinfo->is_camera) {
- /* setup input path */
- if (vpfe_cfg->setup_input &&
- vpfe_cfg->setup_input(sdinfo->grp_id) < 0) {
- ret = -EFAULT;
- v4l2_info(&vpfe_dev->v4l2_dev,
- "could not setup input for %s\n",
- sdinfo->module_name);
- goto probe_sd_out;
- }
- /* Load up the subdevice */
- vpfe_dev->sd[k] =
- v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
- i2c_adap, &sdinfo->board_info,
- NULL);
- if (vpfe_dev->sd[k]) {
- v4l2_info(&vpfe_dev->v4l2_dev,
- "v4l2 sub device %s registered\n",
- sdinfo->module_name);
-
- vpfe_dev->sd[k]->grp_id = sdinfo->grp_id;
- k++;
-
- sdinfo->registered = 1;
- }
- } else {
- v4l2_info(&vpfe_dev->v4l2_dev,
- "v4l2 sub device %s is not registered\n",
- sdinfo->module_name);
- }
- }
- vpfe_dev->num_ext_subdevs = k;
-
- return 0;
-
-probe_sd_out:
- kzfree(vpfe_dev->sd);
-
- return ret;
-}
-
-/*
- * vpfe_register_entities() - register all v4l2 subdevs and media entities
- * @vpfe_dev - ptr to vpfe capture device
- *
- * register all v4l2 subdevs, media entities, and creates links
- * between entities
- */
-static int vpfe_register_entities(struct vpfe_device *vpfe_dev)
-{
- unsigned int flags = 0;
- int ret;
- int i;
-
- /* register i2c devices first */
- ret = register_i2c_devices(vpfe_dev);
- if (ret)
- return ret;
-
- /* register rest of the sub-devs */
- ret = vpfe_isif_register_entities(&vpfe_dev->vpfe_isif,
- &vpfe_dev->v4l2_dev);
- if (ret)
- return ret;
-
- ret = vpfe_ipipeif_register_entities(&vpfe_dev->vpfe_ipipeif,
- &vpfe_dev->v4l2_dev);
- if (ret)
- goto out_isif_register;
-
- ret = vpfe_ipipe_register_entities(&vpfe_dev->vpfe_ipipe,
- &vpfe_dev->v4l2_dev);
- if (ret)
- goto out_ipipeif_register;
-
- ret = vpfe_resizer_register_entities(&vpfe_dev->vpfe_resizer,
- &vpfe_dev->v4l2_dev);
- if (ret)
- goto out_ipipe_register;
-
- /* create links now, starting with external(i2c) entities */
- for (i = 0; i < vpfe_dev->num_ext_subdevs; i++)
- /*
- * if entity has no pads (ex: amplifier),
- * can't establish link
- */
- if (vpfe_dev->sd[i]->entity.num_pads) {
- ret = media_create_pad_link(&vpfe_dev->sd[i]->entity,
- 0, &vpfe_dev->vpfe_isif.subdev.entity,
- 0, flags);
- if (ret < 0)
- goto out_resizer_register;
- }
-
- ret = media_create_pad_link(&vpfe_dev->vpfe_isif.subdev.entity, 1,
- &vpfe_dev->vpfe_ipipeif.subdev.entity,
- 0, flags);
- if (ret < 0)
- goto out_resizer_register;
-
- ret = media_create_pad_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1,
- &vpfe_dev->vpfe_ipipe.subdev.entity,
- 0, flags);
- if (ret < 0)
- goto out_resizer_register;
-
- ret = media_create_pad_link(&vpfe_dev->vpfe_ipipe.subdev.entity,
- 1, &vpfe_dev->vpfe_resizer.crop_resizer.subdev.entity,
- 0, flags);
- if (ret < 0)
- goto out_resizer_register;
-
- ret = media_create_pad_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1,
- &vpfe_dev->vpfe_resizer.crop_resizer.subdev.entity,
- 0, flags);
- if (ret < 0)
- goto out_resizer_register;
-
- ret = v4l2_device_register_subdev_nodes(&vpfe_dev->v4l2_dev);
- if (ret < 0)
- goto out_resizer_register;
-
- return 0;
-
-out_resizer_register:
- vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer);
-out_ipipe_register:
- vpfe_ipipe_unregister_entities(&vpfe_dev->vpfe_ipipe);
-out_ipipeif_register:
- vpfe_ipipeif_unregister_entities(&vpfe_dev->vpfe_ipipeif);
-out_isif_register:
- vpfe_isif_unregister_entities(&vpfe_dev->vpfe_isif);
-
- return ret;
-}
-
-/*
- * vpfe_unregister_entities() - unregister all v4l2 subdevs and media entities
- * @vpfe_dev - ptr to vpfe capture device
- *
- * unregister all v4l2 subdevs and media entities
- */
-static void vpfe_unregister_entities(struct vpfe_device *vpfe_dev)
-{
- vpfe_isif_unregister_entities(&vpfe_dev->vpfe_isif);
- vpfe_ipipeif_unregister_entities(&vpfe_dev->vpfe_ipipeif);
- vpfe_ipipe_unregister_entities(&vpfe_dev->vpfe_ipipe);
- vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer);
-}
-
-/*
- * vpfe_cleanup_modules() - cleanup all non-i2c v4l2 subdevs
- * @vpfe_dev - ptr to vpfe capture device
- * @pdev - pointer to platform device
- *
- * cleanup all v4l2 subdevs
- */
-static void vpfe_cleanup_modules(struct vpfe_device *vpfe_dev,
- struct platform_device *pdev)
-{
- vpfe_isif_cleanup(&vpfe_dev->vpfe_isif, pdev);
- vpfe_ipipeif_cleanup(&vpfe_dev->vpfe_ipipeif, pdev);
- vpfe_ipipe_cleanup(&vpfe_dev->vpfe_ipipe, pdev);
- vpfe_resizer_cleanup(&vpfe_dev->vpfe_resizer, pdev);
-}
-
-/*
- * vpfe_initialize_modules() - initialize all non-i2c v4l2 subdevs
- * @vpfe_dev - ptr to vpfe capture device
- * @pdev - pointer to platform device
- *
- * initialize all v4l2 subdevs and media entities
- */
-static int vpfe_initialize_modules(struct vpfe_device *vpfe_dev,
- struct platform_device *pdev)
-{
- int ret;
-
- ret = vpfe_isif_init(&vpfe_dev->vpfe_isif, pdev);
- if (ret)
- return ret;
-
- ret = vpfe_ipipeif_init(&vpfe_dev->vpfe_ipipeif, pdev);
- if (ret)
- goto out_isif_init;
-
- ret = vpfe_ipipe_init(&vpfe_dev->vpfe_ipipe, pdev);
- if (ret)
- goto out_ipipeif_init;
-
- ret = vpfe_resizer_init(&vpfe_dev->vpfe_resizer, pdev);
- if (ret)
- goto out_ipipe_init;
-
- return 0;
-
-out_ipipe_init:
- vpfe_ipipe_cleanup(&vpfe_dev->vpfe_ipipe, pdev);
-out_ipipeif_init:
- vpfe_ipipeif_cleanup(&vpfe_dev->vpfe_ipipeif, pdev);
-out_isif_init:
- vpfe_isif_cleanup(&vpfe_dev->vpfe_isif, pdev);
-
- return ret;
-}
-
-/*
- * vpfe_probe() : vpfe probe function
- * @pdev: platform device pointer
- *
- * This function creates device entries by register itself to the V4L2 driver
- * and initializes fields of each device objects
- */
-static int vpfe_probe(struct platform_device *pdev)
-{
- struct vpfe_device *vpfe_dev;
- struct resource *res1;
- int ret = -ENOMEM;
-
- vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL);
- if (!vpfe_dev)
- return ret;
-
- if (pdev->dev.platform_data == NULL) {
- v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n");
- ret = -ENOENT;
- goto probe_free_dev_mem;
- }
-
- vpfe_dev->cfg = pdev->dev.platform_data;
- if (vpfe_dev->cfg->card_name == NULL ||
- vpfe_dev->cfg->sub_devs == NULL) {
- v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n");
- ret = -ENOENT;
- goto probe_free_dev_mem;
- }
-
- /* Get VINT0 irq resource */
- res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res1) {
- v4l2_err(pdev->dev.driver,
- "Unable to get interrupt for VINT0\n");
- ret = -ENOENT;
- goto probe_free_dev_mem;
- }
- vpfe_dev->ccdc_irq0 = res1->start;
-
- /* Get VINT1 irq resource */
- res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
- if (!res1) {
- v4l2_err(pdev->dev.driver,
- "Unable to get interrupt for VINT1\n");
- ret = -ENOENT;
- goto probe_free_dev_mem;
- }
- vpfe_dev->ccdc_irq1 = res1->start;
-
- /* Get DMA irq resource */
- res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
- if (!res1) {
- v4l2_err(pdev->dev.driver,
- "Unable to get interrupt for DMA\n");
- ret = -ENOENT;
- goto probe_free_dev_mem;
- }
- vpfe_dev->imp_dma_irq = res1->start;
-
- vpfe_dev->pdev = &pdev->dev;
-
- /* enable vpss clocks */
- ret = vpfe_enable_clock(vpfe_dev);
- if (ret)
- goto probe_free_dev_mem;
-
- ret = vpfe_initialize_modules(vpfe_dev, pdev);
- if (ret)
- goto probe_disable_clock;
-
- vpfe_dev->media_dev.dev = vpfe_dev->pdev;
- strscpy((char *)&vpfe_dev->media_dev.model, "davinci-media",
- sizeof(vpfe_dev->media_dev.model));
-
- ret = media_device_register(&vpfe_dev->media_dev);
- if (ret) {
- v4l2_err(pdev->dev.driver,
- "Unable to register media device.\n");
- goto probe_out_entities_cleanup;
- }
-
- vpfe_dev->v4l2_dev.mdev = &vpfe_dev->media_dev;
- ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev);
- if (ret) {
- v4l2_err(pdev->dev.driver, "Unable to register v4l2 device.\n");
- goto probe_out_media_unregister;
- }
-
- v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n");
- /* set the driver data in platform device */
- platform_set_drvdata(pdev, vpfe_dev);
- /* register subdevs/entities */
- ret = vpfe_register_entities(vpfe_dev);
- if (ret)
- goto probe_out_v4l2_unregister;
-
- ret = vpfe_attach_irq(vpfe_dev);
- if (ret)
- goto probe_out_entities_unregister;
-
- return 0;
-
-probe_out_entities_unregister:
- vpfe_unregister_entities(vpfe_dev);
- kzfree(vpfe_dev->sd);
-probe_out_v4l2_unregister:
- v4l2_device_unregister(&vpfe_dev->v4l2_dev);
-probe_out_media_unregister:
- media_device_unregister(&vpfe_dev->media_dev);
-probe_out_entities_cleanup:
- vpfe_cleanup_modules(vpfe_dev, pdev);
-probe_disable_clock:
- vpfe_disable_clock(vpfe_dev);
-probe_free_dev_mem:
- kzfree(vpfe_dev);
-
- return ret;
-}
-
-/*
- * vpfe_remove : This function un-registers device from V4L2 driver
- */
-static int vpfe_remove(struct platform_device *pdev)
-{
- struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
-
- v4l2_info(pdev->dev.driver, "%s\n", __func__);
-
- kzfree(vpfe_dev->sd);
- vpfe_detach_irq(vpfe_dev);
- vpfe_unregister_entities(vpfe_dev);
- vpfe_cleanup_modules(vpfe_dev, pdev);
- v4l2_device_unregister(&vpfe_dev->v4l2_dev);
- media_device_unregister(&vpfe_dev->media_dev);
- vpfe_disable_clock(vpfe_dev);
- kzfree(vpfe_dev);
-
- return 0;
-}
-
-static struct platform_driver vpfe_driver = {
- .driver = {
- .name = CAPTURE_DRV_NAME,
- },
- .probe = vpfe_probe,
- .remove = vpfe_remove,
-};
-
-module_platform_driver(vpfe_driver);
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h
deleted file mode 100644
index fe4a421b5dba..000000000000
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_MC_CAPTURE_H
-#define _DAVINCI_VPFE_MC_CAPTURE_H
-
-#include "dm365_ipipe.h"
-#include "dm365_ipipeif.h"
-#include "dm365_isif.h"
-#include "dm365_resizer.h"
-#include "vpfe_video.h"
-
-#define VPFE_MAJOR_RELEASE 0
-#define VPFE_MINOR_RELEASE 0
-#define VPFE_BUILD 1
-#define VPFE_CAPTURE_VERSION_CODE ((VPFE_MAJOR_RELEASE << 16) | \
- (VPFE_MINOR_RELEASE << 8) | \
- VPFE_BUILD)
-
-/* IPIPE hardware limits */
-#define IPIPE_MAX_OUTPUT_WIDTH_A 2176
-#define IPIPE_MAX_OUTPUT_WIDTH_B 640
-
-/* Based on max resolution supported. QXGA */
-#define IPIPE_MAX_OUTPUT_HEIGHT_A 1536
-/* Based on max resolution supported. VGA */
-#define IPIPE_MAX_OUTPUT_HEIGHT_B 480
-
-#define to_vpfe_device(ptr_module) \
- container_of(ptr_module, struct vpfe_device, vpfe_##ptr_module)
-#define to_device(ptr_module) \
- (to_vpfe_device(ptr_module)->dev)
-
-struct vpfe_device {
- /* external registered sub devices */
- struct v4l2_subdev **sd;
- /* number of registered external subdevs */
- unsigned int num_ext_subdevs;
- /* vpfe cfg */
- struct vpfe_config *cfg;
- /* clock ptrs for vpfe capture */
- struct clk **clks;
- /* V4l2 device */
- struct v4l2_device v4l2_dev;
- /* parent device */
- struct device *pdev;
- /* IRQ number for DMA transfer completion at the image processor */
- unsigned int imp_dma_irq;
- /* CCDC IRQs used when CCDC/ISIF output to SDRAM */
- unsigned int ccdc_irq0;
- unsigned int ccdc_irq1;
- /* media device */
- struct media_device media_dev;
- /* ccdc subdevice */
- struct vpfe_isif_device vpfe_isif;
- /* ipipeif subdevice */
- struct vpfe_ipipeif_device vpfe_ipipeif;
- /* ipipe subdevice */
- struct vpfe_ipipe_device vpfe_ipipe;
- /* resizer subdevice */
- struct vpfe_resizer_device vpfe_resizer;
-};
-
-/* File handle structure */
-struct vpfe_fh {
- struct v4l2_fh vfh;
- struct vpfe_video_device *video;
- /* Indicates whether this file handle is doing IO */
- u8 io_allowed;
-};
-
-void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus,
- struct v4l2_pix_format *pix);
-
-#endif /* _DAVINCI_VPFE_MC_CAPTURE_H */
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
deleted file mode 100644
index ab6bc452d9f6..000000000000
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <media/v4l2-ioctl.h>
-
-#include "vpfe.h"
-#include "vpfe_mc_capture.h"
-
-static int debug;
-
-/* get v4l2 subdev pointer to external subdev which is active */
-static struct media_entity *vpfe_get_input_entity
- (struct vpfe_video_device *video)
-{
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct media_pad *remote;
-
- remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]);
- if (!remote) {
- pr_err("Invalid media connection to isif/ccdc\n");
- return NULL;
- }
- return remote->entity;
-}
-
-/* updates external subdev(sensor/decoder) which is active */
-static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video)
-{
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_config *vpfe_cfg;
- struct v4l2_subdev *subdev;
- struct media_pad *remote;
- int i;
-
- remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]);
- if (!remote) {
- pr_err("Invalid media connection to isif/ccdc\n");
- return -EINVAL;
- }
-
- subdev = media_entity_to_v4l2_subdev(remote->entity);
- vpfe_cfg = vpfe_dev->pdev->platform_data;
- for (i = 0; i < vpfe_cfg->num_subdevs; i++) {
- if (!strcmp(vpfe_cfg->sub_devs[i].module_name, subdev->name)) {
- video->current_ext_subdev = &vpfe_cfg->sub_devs[i];
- break;
- }
- }
-
- /* if user not linked decoder/sensor to isif/ccdc */
- if (i == vpfe_cfg->num_subdevs) {
- pr_err("Invalid media chain connection to isif/ccdc\n");
- return -EINVAL;
- }
- /* find the v4l2 subdev pointer */
- for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) {
- if (!strcmp(video->current_ext_subdev->module_name,
- vpfe_dev->sd[i]->name))
- video->current_ext_subdev->subdev = vpfe_dev->sd[i];
- }
- return 0;
-}
-
-/* get the subdev which is connected to the output video node */
-static struct v4l2_subdev *
-vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad)
-{
- struct media_pad *remote = media_entity_remote_pad(&video->pad);
-
- if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
- return NULL;
- if (pad)
- *pad = remote->index;
- return media_entity_to_v4l2_subdev(remote->entity);
-}
-
-/* get the format set at output pad of the adjacent subdev */
-static int
-__vpfe_video_get_format(struct vpfe_video_device *video,
- struct v4l2_format *format)
-{
- struct v4l2_subdev_format fmt;
- struct v4l2_subdev *subdev;
- struct media_pad *remote;
- u32 pad;
- int ret;
-
- subdev = vpfe_video_remote_subdev(video, &pad);
- if (!subdev)
- return -EINVAL;
-
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- remote = media_entity_remote_pad(&video->pad);
- fmt.pad = remote->index;
-
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
- if (ret == -ENOIOCTLCMD)
- return -EINVAL;
-
- format->type = video->type;
- /* convert mbus_format to v4l2_format */
- v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
- mbus_to_pix(&fmt.format, &format->fmt.pix);
-
- return 0;
-}
-
-/* make a note of pipeline details */
-static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
-{
- struct media_graph graph;
- struct media_entity *entity = &video->video_dev.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
- struct vpfe_pipeline *pipe = &video->pipe;
- struct vpfe_video_device *far_end = NULL;
- int ret;
-
- pipe->input_num = 0;
- pipe->output_num = 0;
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- pipe->inputs[pipe->input_num++] = video;
- else
- pipe->outputs[pipe->output_num++] = video;
-
- mutex_lock(&mdev->graph_mutex);
- ret = media_graph_walk_init(&graph, mdev);
- if (ret) {
- mutex_unlock(&mdev->graph_mutex);
- return -ENOMEM;
- }
- media_graph_walk_start(&graph, entity);
- while ((entity = media_graph_walk_next(&graph))) {
- if (entity == &video->video_dev.entity)
- continue;
- if (!is_media_entity_v4l2_video_device(entity))
- continue;
- far_end = to_vpfe_video(media_entity_to_video_device(entity));
- if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- pipe->inputs[pipe->input_num++] = far_end;
- else
- pipe->outputs[pipe->output_num++] = far_end;
- }
- media_graph_walk_cleanup(&graph);
- mutex_unlock(&mdev->graph_mutex);
-
- return 0;
-}
-
-/* update pipe state selected by user */
-static int vpfe_update_pipe_state(struct vpfe_video_device *video)
-{
- struct vpfe_pipeline *pipe = &video->pipe;
- int ret;
-
- ret = vpfe_prepare_pipeline(video);
- if (ret)
- return ret;
-
- /*
- * Find out if there is any input video
- * if yes, it is single shot.
- */
- if (pipe->input_num == 0) {
- pipe->state = VPFE_PIPELINE_STREAM_CONTINUOUS;
- ret = vpfe_update_current_ext_subdev(video);
- if (ret) {
- pr_err("Invalid external subdev\n");
- return ret;
- }
- } else {
- pipe->state = VPFE_PIPELINE_STREAM_SINGLESHOT;
- }
- video->initialized = 1;
- video->skip_frame_count = 1;
- video->skip_frame_count_init = 1;
- return 0;
-}
-
-/* checks whether pipeline is ready for enabling */
-int vpfe_video_is_pipe_ready(struct vpfe_pipeline *pipe)
-{
- int i;
-
- for (i = 0; i < pipe->input_num; i++)
- if (!pipe->inputs[i]->started ||
- pipe->inputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED)
- return 0;
- for (i = 0; i < pipe->output_num; i++)
- if (!pipe->outputs[i]->started ||
- pipe->outputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED)
- return 0;
- return 1;
-}
-
-/*
- * Validate a pipeline by checking both ends of all links for format
- * discrepancies.
- *
- * Return 0 if all formats match, or -EPIPE if at least one link is found with
- * different formats on its two ends.
- */
-static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
-{
- struct v4l2_subdev_format fmt_source;
- struct v4l2_subdev_format fmt_sink;
- struct v4l2_subdev *subdev;
- struct media_pad *pad;
- int ret;
-
- /*
- * Should not matter if it is output[0] or 1 as
- * the general ideas is to traverse backwards and
- * the fact that the out video node always has the
- * format of the connected pad.
- */
- subdev = vpfe_video_remote_subdev(pipe->outputs[0], NULL);
- if (!subdev)
- return -EPIPE;
-
- while (1) {
- /* Retrieve the sink format */
- pad = &subdev->entity.pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
-
- fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt_sink.pad = pad->index;
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL,
- &fmt_sink);
-
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return -EPIPE;
-
- /* Retrieve the source format */
- pad = media_entity_remote_pad(pad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- break;
-
- subdev = media_entity_to_v4l2_subdev(pad->entity);
-
- fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt_source.pad = pad->index;
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return -EPIPE;
-
- /* Check if the two ends match */
- if (fmt_source.format.code != fmt_sink.format.code ||
- fmt_source.format.width != fmt_sink.format.width ||
- fmt_source.format.height != fmt_sink.format.height)
- return -EPIPE;
- }
- return 0;
-}
-
-/*
- * vpfe_pipeline_enable() - Enable streaming on a pipeline
- * @vpfe_dev: vpfe device
- * @pipe: vpfe pipeline
- *
- * Walk the entities chain starting at the pipeline output video node and start
- * all modules in the chain in the given mode.
- *
- * Return 0 if successful, or the return value of the failed video::s_stream
- * operation otherwise.
- */
-static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
-{
- struct media_entity *entity;
- struct v4l2_subdev *subdev;
- struct media_device *mdev;
- int ret;
-
- if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
- entity = vpfe_get_input_entity(pipe->outputs[0]);
- else
- entity = &pipe->inputs[0]->video_dev.entity;
-
- mdev = entity->graph_obj.mdev;
- mutex_lock(&mdev->graph_mutex);
- ret = media_graph_walk_init(&pipe->graph, mdev);
- if (ret)
- goto out;
- media_graph_walk_start(&pipe->graph, entity);
- while ((entity = media_graph_walk_next(&pipe->graph))) {
-
- if (!is_media_entity_v4l2_subdev(entity))
- continue;
- subdev = media_entity_to_v4l2_subdev(entity);
- ret = v4l2_subdev_call(subdev, video, s_stream, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- break;
- }
-out:
- if (ret)
- media_graph_walk_cleanup(&pipe->graph);
- mutex_unlock(&mdev->graph_mutex);
- return ret;
-}
-
-/*
- * vpfe_pipeline_disable() - Disable streaming on a pipeline
- * @vpfe_dev: vpfe device
- * @pipe: VPFE pipeline
- *
- * Walk the entities chain starting at the pipeline output video node and stop
- * all modules in the chain.
- *
- * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
- * can't be stopped.
- */
-static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
-{
- struct media_entity *entity;
- struct v4l2_subdev *subdev;
- struct media_device *mdev;
- int ret = 0;
-
- if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
- entity = vpfe_get_input_entity(pipe->outputs[0]);
- else
- entity = &pipe->inputs[0]->video_dev.entity;
-
- mdev = entity->graph_obj.mdev;
- mutex_lock(&mdev->graph_mutex);
- media_graph_walk_start(&pipe->graph, entity);
-
- while ((entity = media_graph_walk_next(&pipe->graph))) {
-
- if (!is_media_entity_v4l2_subdev(entity))
- continue;
- subdev = media_entity_to_v4l2_subdev(entity);
- ret = v4l2_subdev_call(subdev, video, s_stream, 0);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- break;
- }
- mutex_unlock(&mdev->graph_mutex);
-
- media_graph_walk_cleanup(&pipe->graph);
- return ret ? -ETIMEDOUT : 0;
-}
-
-/*
- * vpfe_pipeline_set_stream() - Enable/disable streaming on a pipeline
- * @vpfe_dev: VPFE device
- * @pipe: VPFE pipeline
- * @state: Stream state (stopped or active)
- *
- * Set the pipeline to the given stream state.
- *
- * Return 0 if successful, or the return value of the failed video::s_stream
- * operation otherwise.
- */
-static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe,
- enum vpfe_pipeline_stream_state state)
-{
- if (state == VPFE_PIPELINE_STREAM_STOPPED)
- return vpfe_pipeline_disable(pipe);
-
- return vpfe_pipeline_enable(pipe);
-}
-
-static int all_videos_stopped(struct vpfe_video_device *video)
-{
- struct vpfe_pipeline *pipe = &video->pipe;
- int i;
-
- for (i = 0; i < pipe->input_num; i++)
- if (pipe->inputs[i]->started)
- return 0;
- for (i = 0; i < pipe->output_num; i++)
- if (pipe->outputs[i]->started)
- return 0;
- return 1;
-}
-
-/*
- * vpfe_open() - open video device
- * @file: file pointer
- *
- * initialize media pipeline state, allocate memory for file handle
- *
- * Return 0 if successful, or the return -ENODEV otherwise.
- */
-static int vpfe_open(struct file *file)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_fh *handle;
-
- /* Allocate memory for the file handle object */
- handle = kzalloc(sizeof(struct vpfe_fh), GFP_KERNEL);
-
- if (!handle)
- return -ENOMEM;
-
- v4l2_fh_init(&handle->vfh, &video->video_dev);
- v4l2_fh_add(&handle->vfh);
-
- mutex_lock(&video->lock);
- /* If decoder is not initialized. initialize it */
- if (!video->initialized && vpfe_update_pipe_state(video)) {
- mutex_unlock(&video->lock);
- v4l2_fh_del(&handle->vfh);
- v4l2_fh_exit(&handle->vfh);
- kfree(handle);
- return -ENODEV;
- }
- /* Increment device users counter */
- video->usrs++;
- /* Set io_allowed member to false */
- handle->io_allowed = 0;
- handle->video = video;
- file->private_data = &handle->vfh;
- mutex_unlock(&video->lock);
-
- return 0;
-}
-
-/* get the next buffer available from dma queue */
-static unsigned long
-vpfe_video_get_next_buffer(struct vpfe_video_device *video)
-{
- video->cur_frm = video->next_frm =
- list_entry(video->dma_queue.next,
- struct vpfe_cap_buffer, list);
-
- list_del(&video->next_frm->list);
- video->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
- return vb2_dma_contig_plane_dma_addr(&video->next_frm->vb.vb2_buf, 0);
-}
-
-/* schedule the next buffer which is available on dma queue */
-void vpfe_video_schedule_next_buffer(struct vpfe_video_device *video)
-{
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- unsigned long addr;
-
- if (list_empty(&video->dma_queue))
- return;
-
- video->next_frm = list_entry(video->dma_queue.next,
- struct vpfe_cap_buffer, list);
-
- if (video->pipe.state == VPFE_PIPELINE_STREAM_SINGLESHOT)
- video->cur_frm = video->next_frm;
-
- list_del(&video->next_frm->list);
- video->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
- addr = vb2_dma_contig_plane_dma_addr(&video->next_frm->vb.vb2_buf, 0);
- video->ops->queue(vpfe_dev, addr);
- video->state = VPFE_VIDEO_BUFFER_QUEUED;
-}
-
-/* schedule the buffer for capturing bottom field */
-void vpfe_video_schedule_bottom_field(struct vpfe_video_device *video)
-{
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- unsigned long addr;
-
- addr = vb2_dma_contig_plane_dma_addr(&video->cur_frm->vb.vb2_buf, 0);
- addr += video->field_off;
- video->ops->queue(vpfe_dev, addr);
-}
-
-/* make buffer available for dequeue */
-void vpfe_video_process_buffer_complete(struct vpfe_video_device *video)
-{
- struct vpfe_pipeline *pipe = &video->pipe;
-
- video->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
- vb2_buffer_done(&video->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
- if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
- video->cur_frm = video->next_frm;
-}
-
-/* vpfe_stop_capture() - stop streaming */
-static void vpfe_stop_capture(struct vpfe_video_device *video)
-{
- struct vpfe_pipeline *pipe = &video->pipe;
-
- video->started = 0;
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return;
- if (all_videos_stopped(video))
- vpfe_pipeline_set_stream(pipe,
- VPFE_PIPELINE_STREAM_STOPPED);
-}
-
-/*
- * vpfe_release() - release video device
- * @file: file pointer
- *
- * deletes buffer queue, frees the buffers and the vpfe file handle
- *
- * Return 0
- */
-static int vpfe_release(struct file *file)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct v4l2_fh *vfh = file->private_data;
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_fh *fh = container_of(vfh, struct vpfe_fh, vfh);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
-
- /* Get the device lock */
- mutex_lock(&video->lock);
- /* if this instance is doing IO */
- if (fh->io_allowed) {
- if (video->started) {
- vpfe_stop_capture(video);
- /*
- * mark pipe state as stopped in vpfe_release(),
- * as app might call streamon() after streamoff()
- * in which case driver has to start streaming.
- */
- video->pipe.state = VPFE_PIPELINE_STREAM_STOPPED;
- vb2_streamoff(&video->buffer_queue,
- video->buffer_queue.type);
- }
- video->io_usrs = 0;
- /* Free buffers allocated */
- vb2_queue_release(&video->buffer_queue);
- }
- /* Decrement device users counter */
- video->usrs--;
- v4l2_fh_del(&fh->vfh);
- v4l2_fh_exit(&fh->vfh);
- /* If this is the last file handle */
- if (!video->usrs)
- video->initialized = 0;
- mutex_unlock(&video->lock);
- file->private_data = NULL;
- /* Free memory allocated to file handle object */
- v4l2_fh_del(vfh);
- kzfree(fh);
- return 0;
-}
-
-/*
- * vpfe_mmap() - It is used to map kernel space buffers
- * into user spaces
- */
-static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
- return vb2_mmap(&video->buffer_queue, vma);
-}
-
-/*
- * vpfe_poll() - It is used for select/poll system call
- */
-static __poll_t vpfe_poll(struct file *file, poll_table *wait)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
- if (video->started)
- return vb2_poll(&video->buffer_queue, file, wait);
- return 0;
-}
-
-/* vpfe capture driver file operations */
-static const struct v4l2_file_operations vpfe_fops = {
- .owner = THIS_MODULE,
- .open = vpfe_open,
- .release = vpfe_release,
- .unlocked_ioctl = video_ioctl2,
- .mmap = vpfe_mmap,
- .poll = vpfe_poll
-};
-
-/*
- * vpfe_querycap() - query capabilities of video device
- * @file: file pointer
- * @priv: void pointer
- * @cap: pointer to v4l2_capability structure
- *
- * fills v4l2 capabilities structure
- *
- * Return 0
- */
-static int vpfe_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
-
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
- V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
- strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
- strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
- strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
-
- return 0;
-}
-
-/*
- * vpfe_g_fmt() - get the format which is active on video device
- * @file: file pointer
- * @priv: void pointer
- * @fmt: pointer to v4l2_format structure
- *
- * fills v4l2 format structure with active format
- *
- * Return 0
- */
-static int vpfe_g_fmt(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt\n");
- /* Fill in the information about format */
- *fmt = video->fmt;
- return 0;
-}
-
-/*
- * vpfe_enum_fmt() - enum formats supported on media chain
- * @file: file pointer
- * @priv: void pointer
- * @fmt: pointer to v4l2_fmtdesc structure
- *
- * fills v4l2_fmtdesc structure with output format set on adjacent subdev,
- * only one format is enumearted as subdevs are already configured
- *
- * Return 0 if successful, error code otherwise
- */
-static int vpfe_enum_fmt(struct file *file, void *priv,
- struct v4l2_fmtdesc *fmt)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct v4l2_subdev_format sd_fmt;
- struct v4l2_mbus_framefmt mbus;
- struct v4l2_subdev *subdev;
- struct v4l2_format format;
- struct media_pad *remote;
- int ret;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt\n");
-
- /*
- * since already subdev pad format is set,
- * only one pixel format is available
- */
- if (fmt->index > 0) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid index\n");
- return -EINVAL;
- }
- /* get the remote pad */
- remote = media_entity_remote_pad(&video->pad);
- if (!remote) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "invalid remote pad for video node\n");
- return -EINVAL;
- }
- /* get the remote subdev */
- subdev = vpfe_video_remote_subdev(video, NULL);
- if (!subdev) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "invalid remote subdev for video node\n");
- return -EINVAL;
- }
- sd_fmt.pad = remote->index;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- /* get output format of remote subdev */
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &sd_fmt);
- if (ret) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "invalid remote subdev for video node\n");
- return ret;
- }
- /* convert to pix format */
- mbus.code = sd_fmt.format.code;
- mbus_to_pix(&mbus, &format.fmt.pix);
- /* copy the result */
- fmt->pixelformat = format.fmt.pix.pixelformat;
-
- return 0;
-}
-
-/*
- * vpfe_s_fmt() - set the format on video device
- * @file: file pointer
- * @priv: void pointer
- * @fmt: pointer to v4l2_format structure
- *
- * validate and set the format on video device
- *
- * Return 0 on success, error code otherwise
- */
-static int vpfe_s_fmt(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct v4l2_format format;
- int ret;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt\n");
- /* If streaming is started, return error */
- if (video->started) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
- return -EBUSY;
- }
- /* get adjacent subdev's output pad format */
- ret = __vpfe_video_get_format(video, &format);
- if (ret)
- return ret;
- *fmt = format;
- video->fmt = *fmt;
- return 0;
-}
-
-/*
- * vpfe_try_fmt() - try the format on video device
- * @file: file pointer
- * @priv: void pointer
- * @fmt: pointer to v4l2_format structure
- *
- * validate the format, update with correct format
- * based on output format set on adjacent subdev
- *
- * Return 0 on success, error code otherwise
- */
-static int vpfe_try_fmt(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct v4l2_format format;
- int ret;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt\n");
- /* get adjacent subdev's output pad format */
- ret = __vpfe_video_get_format(video, &format);
- if (ret)
- return ret;
-
- *fmt = format;
- return 0;
-}
-
-/*
- * vpfe_enum_input() - enum inputs supported on media chain
- * @file: file pointer
- * @priv: void pointer
- * @fmt: pointer to v4l2_fmtdesc structure
- *
- * fills v4l2_input structure with input available on media chain,
- * only one input is enumearted as media chain is setup by this time
- *
- * Return 0 if successful, -EINVAL is media chain is invalid
- */
-static int vpfe_enum_input(struct file *file, void *priv,
- struct v4l2_input *inp)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_ext_subdev_info *sdinfo = video->current_ext_subdev;
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
- /* enumerate from the subdev user has chosen through mc */
- if (inp->index < sdinfo->num_inputs) {
- memcpy(inp, &sdinfo->inputs[inp->index],
- sizeof(struct v4l2_input));
- return 0;
- }
- return -EINVAL;
-}
-
-/*
- * vpfe_g_input() - get index of the input which is active
- * @file: file pointer
- * @priv: void pointer
- * @index: pointer to unsigned int
- *
- * set index with input index which is active
- */
-static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
-
- *index = video->current_input;
- return 0;
-}
-
-/*
- * vpfe_s_input() - set input which is pointed by input index
- * @file: file pointer
- * @priv: void pointer
- * @index: pointer to unsigned int
- *
- * set input on external subdev
- *
- * Return 0 on success, error code otherwise
- */
-static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_ext_subdev_info *sdinfo;
- struct vpfe_route *route;
- struct v4l2_input *inps;
- u32 output;
- u32 input;
- int ret;
- int i;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
-
- ret = mutex_lock_interruptible(&video->lock);
- if (ret)
- return ret;
- /*
- * If streaming is started return device busy
- * error
- */
- if (video->started) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
- ret = -EBUSY;
- goto unlock_out;
- }
-
- sdinfo = video->current_ext_subdev;
- if (!sdinfo->registered) {
- ret = -EINVAL;
- goto unlock_out;
- }
- if (vpfe_dev->cfg->setup_input &&
- vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) {
- ret = -EFAULT;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "couldn't setup input for %s\n",
- sdinfo->module_name);
- goto unlock_out;
- }
- route = &sdinfo->routes[index];
- if (route && sdinfo->can_route) {
- input = route->input;
- output = route->output;
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
- sdinfo->grp_id, video,
- s_routing, input, output, 0);
- if (ret) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "s_input:error in setting input in decoder\n");
- ret = -EINVAL;
- goto unlock_out;
- }
- }
- /* set standards set by subdev in video device */
- for (i = 0; i < sdinfo->num_inputs; i++) {
- inps = &sdinfo->inputs[i];
- video->video_dev.tvnorms |= inps->std;
- }
- video->current_input = index;
-unlock_out:
- mutex_unlock(&video->lock);
- return ret;
-}
-
-/*
- * vpfe_querystd() - query std which is being input on external subdev
- * @file: file pointer
- * @priv: void pointer
- * @std_id: pointer to v4l2_std_id structure
- *
- * call external subdev through v4l2_device_call_until_err to
- * get the std that is being active.
- *
- * Return 0 on success, error code otherwise
- */
-static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_ext_subdev_info *sdinfo;
- int ret;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
-
- ret = mutex_lock_interruptible(&video->lock);
- sdinfo = video->current_ext_subdev;
- if (ret)
- return ret;
- /* Call querystd function of decoder device */
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- video, querystd, std_id);
- mutex_unlock(&video->lock);
- return ret;
-}
-
-/*
- * vpfe_s_std() - set std on external subdev
- * @file: file pointer
- * @priv: void pointer
- * @std_id: pointer to v4l2_std_id structure
- *
- * set std pointed by std_id on external subdev by calling it using
- * v4l2_device_call_until_err
- *
- * Return 0 on success, error code otherwise
- */
-static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_ext_subdev_info *sdinfo;
- int ret;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
-
- /* Call decoder driver function to set the standard */
- ret = mutex_lock_interruptible(&video->lock);
- if (ret)
- return ret;
- sdinfo = video->current_ext_subdev;
- /* If streaming is started, return device busy error */
- if (video->started) {
- v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
- ret = -EBUSY;
- goto unlock_out;
- }
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- video, s_std, std_id);
- if (ret < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
- video->stdid = V4L2_STD_UNKNOWN;
- goto unlock_out;
- }
- video->stdid = std_id;
-unlock_out:
- mutex_unlock(&video->lock);
- return ret;
-}
-
-static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n");
- *tvnorm = video->stdid;
- return 0;
-}
-
-/*
- * vpfe_enum_dv_timings() - enumerate dv_timings which are supported by
- * to external subdev
- * @file: file pointer
- * @priv: void pointer
- * @timings: pointer to v4l2_enum_dv_timings structure
- *
- * enum dv_timings's which are supported by external subdev through
- * v4l2_subdev_call
- *
- * Return 0 on success, error code otherwise
- */
-static int
-vpfe_enum_dv_timings(struct file *file, void *fh,
- struct v4l2_enum_dv_timings *timings)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
-
- timings->pad = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_dv_timings\n");
- return v4l2_subdev_call(subdev, pad, enum_dv_timings, timings);
-}
-
-/*
- * vpfe_query_dv_timings() - query the dv_timings which is being input
- * to external subdev
- * @file: file pointer
- * @priv: void pointer
- * @timings: pointer to v4l2_dv_timings structure
- *
- * get dv_timings which is being input on external subdev through
- * v4l2_subdev_call
- *
- * Return 0 on success, error code otherwise
- */
-static int
-vpfe_query_dv_timings(struct file *file, void *fh,
- struct v4l2_dv_timings *timings)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_query_dv_timings\n");
- return v4l2_subdev_call(subdev, video, query_dv_timings, timings);
-}
-
-/*
- * vpfe_s_dv_timings() - set dv_timings on external subdev
- * @file: file pointer
- * @priv: void pointer
- * @timings: pointer to v4l2_dv_timings structure
- *
- * set dv_timings pointed by timings on external subdev through
- * v4l2_device_call_until_err, this configures amplifier also
- *
- * Return 0 on success, error code otherwise
- */
-static int
-vpfe_s_dv_timings(struct file *file, void *fh,
- struct v4l2_dv_timings *timings)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_dv_timings\n");
-
- video->stdid = V4L2_STD_UNKNOWN;
- return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
- video->current_ext_subdev->grp_id,
- video, s_dv_timings, timings);
-}
-
-/*
- * vpfe_g_dv_timings() - get dv_timings which is set on external subdev
- * @file: file pointer
- * @priv: void pointer
- * @timings: pointer to v4l2_dv_timings structure
- *
- * get dv_timings which is set on external subdev through
- * v4l2_subdev_call
- *
- * Return 0 on success, error code otherwise
- */
-static int
-vpfe_g_dv_timings(struct file *file, void *fh,
- struct v4l2_dv_timings *timings)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_dv_timings\n");
- return v4l2_subdev_call(subdev, video, g_dv_timings, timings);
-}
-
-/*
- * Videobuf operations
- */
-/*
- * vpfe_buffer_queue_setup : Callback function for buffer setup.
- * @vq: vb2_queue ptr
- * @fmt: v4l2 format
- * @nbuffers: ptr to number of buffers requested by application
- * @nplanes:: contains number of distinct video planes needed to hold a frame
- * @sizes[]: contains the size (in bytes) of each plane.
- * @alloc_devs: ptr to allocation context
- *
- * This callback function is called when reqbuf() is called to adjust
- * the buffer nbuffers and buffer size
- */
-static int
-vpfe_buffer_queue_setup(struct vb2_queue *vq,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], struct device *alloc_devs[])
-{
- struct vpfe_fh *fh = vb2_get_drv_priv(vq);
- struct vpfe_video_device *video = fh->video;
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- unsigned long size;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue_setup\n");
- size = video->fmt.fmt.pix.sizeimage;
-
- if (vq->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - vq->num_buffers;
-
- *nplanes = 1;
- sizes[0] = size;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "nbuffers=%d, size=%lu\n", *nbuffers, size);
- return 0;
-}
-
-/*
- * vpfe_buffer_prepare : callback function for buffer prepare
- * @vb: ptr to vb2_buffer
- *
- * This is the callback function for buffer prepare when vb2_qbuf()
- * function is called. The buffer is prepared and user space virtual address
- * or user address is converted into physical address
- */
-static int vpfe_buffer_prepare(struct vb2_buffer *vb)
-{
- struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpfe_video_device *video = fh->video;
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- unsigned long addr;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n");
-
- /* Initialize buffer */
- vb2_set_plane_payload(vb, 0, video->fmt.fmt.pix.sizeimage);
- if (vb2_plane_vaddr(vb, 0) &&
- vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
- return -EINVAL;
-
- addr = vb2_dma_contig_plane_dma_addr(vb, 0);
- /* Make sure user addresses are aligned to 32 bytes */
- if (!ALIGN(addr, 32))
- return -EINVAL;
-
- return 0;
-}
-
-static void vpfe_buffer_queue(struct vb2_buffer *vb)
-{
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- /* Get the file handle object and device object */
- struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpfe_video_device *video = fh->video;
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_pipeline *pipe = &video->pipe;
- struct vpfe_cap_buffer *buf = container_of(vbuf,
- struct vpfe_cap_buffer, vb);
- unsigned long flags;
- unsigned long empty;
- unsigned long addr;
-
- spin_lock_irqsave(&video->dma_queue_lock, flags);
- empty = list_empty(&video->dma_queue);
- /* add the buffer to the DMA queue */
- list_add_tail(&buf->list, &video->dma_queue);
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
- /* this case happens in case of single shot */
- if (empty && video->started && pipe->state ==
- VPFE_PIPELINE_STREAM_SINGLESHOT &&
- video->state == VPFE_VIDEO_BUFFER_NOT_QUEUED) {
- spin_lock(&video->dma_queue_lock);
- addr = vpfe_video_get_next_buffer(video);
- video->ops->queue(vpfe_dev, addr);
-
- video->state = VPFE_VIDEO_BUFFER_QUEUED;
- spin_unlock(&video->dma_queue_lock);
-
- /* enable h/w each time in single shot */
- if (vpfe_video_is_pipe_ready(pipe))
- vpfe_pipeline_set_stream(pipe,
- VPFE_PIPELINE_STREAM_SINGLESHOT);
- }
-}
-
-/* vpfe_start_capture() - start streaming on all the subdevs */
-static int vpfe_start_capture(struct vpfe_video_device *video)
-{
- struct vpfe_pipeline *pipe = &video->pipe;
- int ret = 0;
-
- video->started = 1;
- if (vpfe_video_is_pipe_ready(pipe))
- ret = vpfe_pipeline_set_stream(pipe, pipe->state);
-
- return ret;
-}
-
-static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count)
-{
- struct vpfe_fh *fh = vb2_get_drv_priv(vq);
- struct vpfe_video_device *video = fh->video;
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- unsigned long addr;
- int ret;
-
- ret = mutex_lock_interruptible(&video->lock);
- if (ret)
- goto streamoff;
-
- /* Get the next frame from the buffer queue */
- video->cur_frm = video->next_frm =
- list_entry(video->dma_queue.next, struct vpfe_cap_buffer, list);
- /* Remove buffer from the buffer queue */
- list_del(&video->cur_frm->list);
- /* Mark state of the current frame to active */
- video->cur_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
- /* Initialize field_id and started member */
- video->field_id = 0;
- addr = vb2_dma_contig_plane_dma_addr(&video->cur_frm->vb.vb2_buf, 0);
- video->ops->queue(vpfe_dev, addr);
- video->state = VPFE_VIDEO_BUFFER_QUEUED;
-
- ret = vpfe_start_capture(video);
- if (ret) {
- struct vpfe_cap_buffer *buf, *tmp;
-
- vb2_buffer_done(&video->cur_frm->vb.vb2_buf,
- VB2_BUF_STATE_QUEUED);
- list_for_each_entry_safe(buf, tmp, &video->dma_queue, list) {
- list_del(&buf->list);
- vb2_buffer_done(&buf->vb.vb2_buf,
- VB2_BUF_STATE_QUEUED);
- }
- goto unlock_out;
- }
-
- mutex_unlock(&video->lock);
-
- return ret;
-unlock_out:
- mutex_unlock(&video->lock);
-streamoff:
- ret = vb2_streamoff(&video->buffer_queue, video->buffer_queue.type);
- return 0;
-}
-
-static int vpfe_buffer_init(struct vb2_buffer *vb)
-{
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct vpfe_cap_buffer *buf = container_of(vbuf,
- struct vpfe_cap_buffer, vb);
-
- INIT_LIST_HEAD(&buf->list);
- return 0;
-}
-
-/* abort streaming and wait for last buffer */
-static void vpfe_stop_streaming(struct vb2_queue *vq)
-{
- struct vpfe_fh *fh = vb2_get_drv_priv(vq);
- struct vpfe_video_device *video = fh->video;
-
- /* release all active buffers */
- if (video->cur_frm == video->next_frm) {
- vb2_buffer_done(&video->cur_frm->vb.vb2_buf,
- VB2_BUF_STATE_ERROR);
- } else {
- if (video->cur_frm != NULL)
- vb2_buffer_done(&video->cur_frm->vb.vb2_buf,
- VB2_BUF_STATE_ERROR);
- if (video->next_frm != NULL)
- vb2_buffer_done(&video->next_frm->vb.vb2_buf,
- VB2_BUF_STATE_ERROR);
- }
-
- while (!list_empty(&video->dma_queue)) {
- video->next_frm = list_entry(video->dma_queue.next,
- struct vpfe_cap_buffer, list);
- list_del(&video->next_frm->list);
- vb2_buffer_done(&video->next_frm->vb.vb2_buf,
- VB2_BUF_STATE_ERROR);
- }
-}
-
-static void vpfe_buf_cleanup(struct vb2_buffer *vb)
-{
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpfe_video_device *video = fh->video;
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_cap_buffer *buf = container_of(vbuf,
- struct vpfe_cap_buffer, vb);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buf_cleanup\n");
- if (vb->state == VB2_BUF_STATE_ACTIVE)
- list_del_init(&buf->list);
-}
-
-static const struct vb2_ops video_qops = {
- .queue_setup = vpfe_buffer_queue_setup,
- .buf_init = vpfe_buffer_init,
- .buf_prepare = vpfe_buffer_prepare,
- .start_streaming = vpfe_start_streaming,
- .stop_streaming = vpfe_stop_streaming,
- .buf_cleanup = vpfe_buf_cleanup,
- .buf_queue = vpfe_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
-};
-
-/*
- * vpfe_reqbufs() - supported REQBUF only once opening
- * the device.
- */
-static int vpfe_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req_buf)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_fh *fh = file->private_data;
- struct vb2_queue *q;
- int ret;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
-
- if (req_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- req_buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT){
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- ret = mutex_lock_interruptible(&video->lock);
- if (ret)
- return ret;
-
- if (video->io_usrs != 0) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
- ret = -EBUSY;
- goto unlock_out;
- }
- video->memory = req_buf->memory;
-
- /* Initialize videobuf2 queue as per the buffer type */
- q = &video->buffer_queue;
- q->type = req_buf->type;
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->drv_priv = fh;
- q->min_buffers_needed = 1;
- q->ops = &video_qops;
- q->mem_ops = &vb2_dma_contig_memops;
- q->buf_struct_size = sizeof(struct vpfe_cap_buffer);
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->dev = vpfe_dev->pdev;
- q->lock = &video->lock;
-
- ret = vb2_queue_init(q);
- if (ret) {
- v4l2_err(&vpfe_dev->v4l2_dev, "vb2_queue_init() failed\n");
- goto unlock_out;
- }
-
- fh->io_allowed = 1;
- video->io_usrs = 1;
- INIT_LIST_HEAD(&video->dma_queue);
- ret = vb2_reqbufs(&video->buffer_queue, req_buf);
-
-unlock_out:
- mutex_unlock(&video->lock);
- return ret;
-}
-
-/*
- * vpfe_querybuf() - query buffers for exchange
- */
-static int vpfe_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
-
- if (video->memory != V4L2_MEMORY_MMAP) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
- return -EINVAL;
- }
-
- /* Call vb2_querybuf to get information */
- return vb2_querybuf(&video->buffer_queue, buf);
-}
-
-/*
- * vpfe_qbuf() - queue buffers for capture or processing
- */
-static int vpfe_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_fh *fh = file->private_data;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
-
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- p->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
- /*
- * If this file handle is not allowed to do IO,
- * return error
- */
- if (!fh->io_allowed) {
- v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
- return -EACCES;
- }
-
- return vb2_qbuf(&video->buffer_queue,
- video->video_dev.v4l2_dev->mdev, p);
-}
-
-/*
- * vpfe_dqbuf() - deque buffer which is done with processing
- */
-static int vpfe_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
-
- return vb2_dqbuf(&video->buffer_queue,
- buf, (file->f_flags & O_NONBLOCK));
-}
-
-/*
- * vpfe_streamon() - start streaming
- * @file: file pointer
- * @priv: void pointer
- * @buf_type: enum v4l2_buf_type
- *
- * queue buffer onto hardware for capture/processing and
- * start all the subdevs which are in media chain
- *
- * Return 0 on success, error code otherwise
- */
-static int vpfe_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_pipeline *pipe = &video->pipe;
- struct vpfe_fh *fh = file->private_data;
- int ret = -EINVAL;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
-
- if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return ret;
- }
- /* If file handle is not allowed IO, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
- return -EACCES;
- }
- /* If buffer queue is empty, return error */
- if (list_empty(&video->buffer_queue.queued_list)) {
- v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
- return -EIO;
- }
- /* Validate the pipeline */
- if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret = vpfe_video_validate_pipeline(pipe);
- if (ret < 0)
- return ret;
- }
- /* Call vb2_streamon to start streaming */
- return vb2_streamon(&video->buffer_queue, buf_type);
-}
-
-/*
- * vpfe_streamoff() - stop streaming
- * @file: file pointer
- * @priv: void pointer
- * @buf_type: enum v4l2_buf_type
- *
- * stop all the subdevs which are in media chain
- *
- * Return 0 on success, error code otherwise
- */
-static int vpfe_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct vpfe_video_device *video = video_drvdata(file);
- struct vpfe_device *vpfe_dev = video->vpfe_dev;
- struct vpfe_fh *fh = file->private_data;
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
-
- if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
-
- /* If io is allowed for this file handle, return error */
- if (!fh->io_allowed) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "fh->io_allowed\n");
- return -EACCES;
- }
-
- /* If streaming is not started, return error */
- if (!video->started) {
- v4l2_err(&vpfe_dev->v4l2_dev, "device is not started\n");
- return -EINVAL;
- }
-
- ret = mutex_lock_interruptible(&video->lock);
- if (ret)
- return ret;
-
- vpfe_stop_capture(video);
- ret = vb2_streamoff(&video->buffer_queue, buf_type);
- mutex_unlock(&video->lock);
-
- return ret;
-}
-
-/* vpfe capture ioctl operations */
-static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
- .vidioc_querycap = vpfe_querycap,
- .vidioc_g_fmt_vid_cap = vpfe_g_fmt,
- .vidioc_s_fmt_vid_cap = vpfe_s_fmt,
- .vidioc_try_fmt_vid_cap = vpfe_try_fmt,
- .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt,
- .vidioc_g_fmt_vid_out = vpfe_g_fmt,
- .vidioc_s_fmt_vid_out = vpfe_s_fmt,
- .vidioc_try_fmt_vid_out = vpfe_try_fmt,
- .vidioc_enum_fmt_vid_out = vpfe_enum_fmt,
- .vidioc_enum_input = vpfe_enum_input,
- .vidioc_g_input = vpfe_g_input,
- .vidioc_s_input = vpfe_s_input,
- .vidioc_querystd = vpfe_querystd,
- .vidioc_s_std = vpfe_s_std,
- .vidioc_g_std = vpfe_g_std,
- .vidioc_enum_dv_timings = vpfe_enum_dv_timings,
- .vidioc_query_dv_timings = vpfe_query_dv_timings,
- .vidioc_s_dv_timings = vpfe_s_dv_timings,
- .vidioc_g_dv_timings = vpfe_g_dv_timings,
- .vidioc_reqbufs = vpfe_reqbufs,
- .vidioc_querybuf = vpfe_querybuf,
- .vidioc_qbuf = vpfe_qbuf,
- .vidioc_dqbuf = vpfe_dqbuf,
- .vidioc_streamon = vpfe_streamon,
- .vidioc_streamoff = vpfe_streamoff,
-};
-
-/* VPFE video init function */
-int vpfe_video_init(struct vpfe_video_device *video, const char *name)
-{
- const char *direction;
- int ret;
-
- switch (video->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- direction = "output";
- video->pad.flags = MEDIA_PAD_FL_SINK;
- video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
-
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- direction = "input";
- video->pad.flags = MEDIA_PAD_FL_SOURCE;
- video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- break;
-
- default:
- return -EINVAL;
- }
- /* Initialize field of video device */
- mutex_init(&video->lock);
- video->video_dev.release = video_device_release;
- video->video_dev.fops = &vpfe_fops;
- video->video_dev.ioctl_ops = &vpfe_ioctl_ops;
- video->video_dev.minor = -1;
- video->video_dev.tvnorms = 0;
- video->video_dev.lock = &video->lock;
- snprintf(video->video_dev.name, sizeof(video->video_dev.name),
- "DAVINCI VIDEO %s %s", name, direction);
-
- spin_lock_init(&video->irqlock);
- spin_lock_init(&video->dma_queue_lock);
- ret = media_entity_pads_init(&video->video_dev.entity,
- 1, &video->pad);
- if (ret < 0)
- return ret;
-
- video_set_drvdata(&video->video_dev, video);
-
- return 0;
-}
-
-/* vpfe video device register function */
-int vpfe_video_register(struct vpfe_video_device *video,
- struct v4l2_device *vdev)
-{
- int ret;
-
- video->video_dev.v4l2_dev = vdev;
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- video->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE;
- else
- video->video_dev.device_caps = V4L2_CAP_VIDEO_OUTPUT;
- video->video_dev.device_caps |= V4L2_CAP_STREAMING;
- ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1);
- if (ret < 0)
- pr_err("%s: could not register video device (%d)\n",
- __func__, ret);
- return ret;
-}
-
-/* vpfe video device unregister function */
-void vpfe_video_unregister(struct vpfe_video_device *video)
-{
- if (video_is_registered(&video->video_dev)) {
- video_unregister_device(&video->video_dev);
- media_entity_cleanup(&video->video_dev.entity);
- }
-}
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.h b/drivers/staging/media/davinci_vpfe/vpfe_video.h
deleted file mode 100644
index 5d01c4883ab4..000000000000
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2012 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Contributors:
- * Manjunath Hadli <manjunath.hadli@ti.com>
- * Prabhakar Lad <prabhakar.lad@ti.com>
- */
-
-#ifndef _DAVINCI_VPFE_VIDEO_H
-#define _DAVINCI_VPFE_VIDEO_H
-
-#include <media/videobuf2-v4l2.h>
-#include <media/videobuf2-dma-contig.h>
-
-struct vpfe_device;
-
-/*
- * struct vpfe_video_operations - VPFE video operations
- * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
- * if there was no buffer previously queued.
- */
-struct vpfe_video_operations {
- int (*queue)(struct vpfe_device *vpfe_dev, unsigned long addr);
-};
-
-enum vpfe_pipeline_stream_state {
- VPFE_PIPELINE_STREAM_STOPPED = 0,
- VPFE_PIPELINE_STREAM_CONTINUOUS = 1,
- VPFE_PIPELINE_STREAM_SINGLESHOT = 2,
-};
-
-enum vpfe_video_state {
- /* indicates that buffer is not queued */
- VPFE_VIDEO_BUFFER_NOT_QUEUED = 0,
- /* indicates that buffer is queued */
- VPFE_VIDEO_BUFFER_QUEUED = 1,
-};
-
-struct vpfe_pipeline {
- /* media pipeline */
- struct media_pipeline *pipe;
- struct media_graph graph;
- /* state of the pipeline, continuous,
- * single-shot or stopped
- */
- enum vpfe_pipeline_stream_state state;
- /* number of active input video entities */
- unsigned int input_num;
- /* number of active output video entities */
- unsigned int output_num;
- /* input video nodes in case of single-shot mode */
- struct vpfe_video_device *inputs[10];
- /* capturing video nodes */
- struct vpfe_video_device *outputs[10];
-};
-
-#define to_vpfe_pipeline(__e) \
- container_of((__e)->pipe, struct vpfe_pipeline, pipe)
-
-#define to_vpfe_video(vdev) \
- container_of(vdev, struct vpfe_video_device, video_dev)
-
-struct vpfe_cap_buffer {
- struct vb2_v4l2_buffer vb;
- struct list_head list;
-};
-
-struct vpfe_video_device {
- /* vpfe device */
- struct vpfe_device *vpfe_dev;
- /* video dev */
- struct video_device video_dev;
- /* media pad of video entity */
- struct media_pad pad;
- /* video operations supported by video device */
- const struct vpfe_video_operations *ops;
- /* type of the video buffers used by user */
- enum v4l2_buf_type type;
- /* Indicates id of the field which is being captured */
- u32 field_id;
- /* pipeline for which video device is part of */
- struct vpfe_pipeline pipe;
- /* Indicates whether streaming started */
- u8 started;
- /* Indicates state of the stream */
- unsigned int state;
- /* current input at the sub device */
- int current_input;
- /*
- * This field keeps track of type of buffer exchange mechanism
- * user has selected
- */
- enum v4l2_memory memory;
- /* number of open instances of the channel */
- u32 usrs;
- /* flag to indicate whether decoder is initialized */
- u8 initialized;
- /* skip frame count */
- u8 skip_frame_count;
- /* skip frame count init value */
- u8 skip_frame_count_init;
- /* time per frame for skipping */
- struct v4l2_fract timeperframe;
- /* ptr to currently selected sub device */
- struct vpfe_ext_subdev_info *current_ext_subdev;
- /* Pointer pointing to current vpfe_cap_buffer */
- struct vpfe_cap_buffer *cur_frm;
- /* Pointer pointing to next vpfe_cap_buffer */
- struct vpfe_cap_buffer *next_frm;
- /* Used to store pixel format */
- struct v4l2_format fmt;
- struct vb2_queue buffer_queue;
- /* Queue of filled frames */
- struct list_head dma_queue;
- spinlock_t irqlock;
- /* IRQ lock for DMA queue */
- spinlock_t dma_queue_lock;
- /* lock used to serialize all video4linux ioctls */
- struct mutex lock;
- /* number of users performing IO */
- u32 io_usrs;
- /* Currently selected or default standard */
- v4l2_std_id stdid;
- /*
- * offset where second field starts from the starting of the
- * buffer for field separated YCbCr formats
- */
- u32 field_off;
-};
-
-int vpfe_video_is_pipe_ready(struct vpfe_pipeline *pipe);
-void vpfe_video_unregister(struct vpfe_video_device *video);
-int vpfe_video_register(struct vpfe_video_device *video,
- struct v4l2_device *vdev);
-int vpfe_video_init(struct vpfe_video_device *video, const char *name);
-void vpfe_video_process_buffer_complete(struct vpfe_video_device *video);
-void vpfe_video_schedule_bottom_field(struct vpfe_video_device *video);
-void vpfe_video_schedule_next_buffer(struct vpfe_video_device *video);
-
-#endif /* _DAVINCI_VPFE_VIDEO_H */
diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig
index be133bbaa68a..de77fe6554e7 100644
--- a/drivers/staging/media/hantro/Kconfig
+++ b/drivers/staging/media/hantro/Kconfig
@@ -20,4 +20,4 @@ config VIDEO_HANTRO_ROCKCHIP
depends on ARCH_ROCKCHIP || COMPILE_TEST
default y
help
- Enable support for RK3288 and RK3399 SoCs.
+ Enable support for RK3288, RK3328, and RK3399 SoCs.
diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile
index 1584acdbf4a3..5d6b0383d280 100644
--- a/drivers/staging/media/hantro/Makefile
+++ b/drivers/staging/media/hantro/Makefile
@@ -4,11 +4,16 @@ hantro-vpu-y += \
hantro_drv.o \
hantro_v4l2.o \
hantro_h1_jpeg_enc.o \
+ hantro_g1_h264_dec.o \
hantro_g1_mpeg2_dec.o \
+ hantro_g1_vp8_dec.o \
rk3399_vpu_hw_jpeg_enc.o \
rk3399_vpu_hw_mpeg2_dec.o \
+ rk3399_vpu_hw_vp8_dec.o \
hantro_jpeg.o \
- hantro_mpeg2.o
+ hantro_h264.o \
+ hantro_mpeg2.o \
+ hantro_vp8.o
hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \
rk3288_vpu_hw.o \
diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h
index 62dcca9ff19c..f670bbde4159 100644
--- a/drivers/staging/media/hantro/hantro.h
+++ b/drivers/staging/media/hantro/hantro.h
@@ -20,11 +20,20 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
#include "hantro_hw.h"
+#define VP8_MB_DIM 16
+#define VP8_MB_WIDTH(w) DIV_ROUND_UP(w, VP8_MB_DIM)
+#define VP8_MB_HEIGHT(h) DIV_ROUND_UP(h, VP8_MB_DIM)
+
+#define H264_MB_DIM 16
+#define H264_MB_WIDTH(w) DIV_ROUND_UP(w, H264_MB_DIM)
+#define H264_MB_HEIGHT(h) DIV_ROUND_UP(h, H264_MB_DIM)
+
#define MPEG2_MB_DIM 16
#define MPEG2_MB_WIDTH(w) DIV_ROUND_UP(w, MPEG2_MB_DIM)
#define MPEG2_MB_HEIGHT(h) DIV_ROUND_UP(h, MPEG2_MB_DIM)
@@ -38,8 +47,9 @@ struct hantro_codec_ops;
#define HANTRO_JPEG_ENCODER BIT(0)
#define HANTRO_ENCODERS 0x0000ffff
-
#define HANTRO_MPEG2_DECODER BIT(16)
+#define HANTRO_VP8_DECODER BIT(17)
+#define HANTRO_H264_DECODER BIT(18)
#define HANTRO_DECODERS 0xffff0000
/**
@@ -96,22 +106,24 @@ struct hantro_variant {
* enum hantro_codec_mode - codec operating mode.
* @HANTRO_MODE_NONE: No operating mode. Used for RAW video formats.
* @HANTRO_MODE_JPEG_ENC: JPEG encoder.
+ * @HANTRO_MODE_H264_DEC: H264 decoder.
* @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder.
+ * @HANTRO_MODE_VP8_DEC: VP8 decoder.
*/
enum hantro_codec_mode {
HANTRO_MODE_NONE = -1,
HANTRO_MODE_JPEG_ENC,
+ HANTRO_MODE_H264_DEC,
HANTRO_MODE_MPEG2_DEC,
+ HANTRO_MODE_VP8_DEC,
};
/*
* struct hantro_ctrl - helper type to declare supported controls
- * @id: V4L2 control ID (V4L2_CID_xxx)
* @codec: codec id this control belong to (HANTRO_JPEG_ENCODER, etc.)
* @cfg: control configuration
*/
struct hantro_ctrl {
- unsigned int id;
unsigned int codec;
struct v4l2_ctrl_config cfg;
};
@@ -215,6 +227,7 @@ struct hantro_dev {
* @codec_ops: Set of operations related to codec mode.
* @jpeg_enc: JPEG-encoding context.
* @mpeg2_dec: MPEG-2-decoding context.
+ * @vp8_dec: VP8-decoding context.
*/
struct hantro_ctx {
struct hantro_dev *dev;
@@ -239,8 +252,10 @@ struct hantro_ctx {
/* Specific for particular codec modes. */
union {
+ struct hantro_h264_dec_hw_ctx h264_dec;
struct hantro_jpeg_enc_hw_ctx jpeg_enc;
struct hantro_mpeg2_dec_hw_ctx mpeg2_dec;
+ struct hantro_vp8_dec_hw_ctx vp8_dec;
};
};
@@ -265,6 +280,12 @@ struct hantro_fmt {
struct v4l2_frmsize_stepwise frmsize;
};
+struct hantro_reg {
+ u32 base;
+ u32 shift;
+ u32 mask;
+};
+
/* Logging helpers */
/**
@@ -343,9 +364,33 @@ static inline u32 vdpu_read(struct hantro_dev *vpu, u32 reg)
return val;
}
+static inline void hantro_reg_write(struct hantro_dev *vpu,
+ const struct hantro_reg *reg,
+ u32 val)
+{
+ u32 v;
+
+ v = vdpu_read(vpu, reg->base);
+ v &= ~(reg->mask << reg->shift);
+ v |= ((val & reg->mask) << reg->shift);
+ vdpu_write_relaxed(vpu, v, reg->base);
+}
+
bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx);
void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id);
dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts);
+static inline struct vb2_v4l2_buffer *
+hantro_get_src_buf(struct hantro_ctx *ctx)
+{
+ return v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+}
+
+static inline struct vb2_v4l2_buffer *
+hantro_get_dst_buf(struct hantro_ctx *ctx)
+{
+ return v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+}
+
#endif /* HANTRO_H_ */
diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c
index c3665f0e87a2..6d9d41170832 100644
--- a/drivers/staging/media/hantro/hantro_drv.c
+++ b/drivers/staging/media/hantro/hantro_drv.c
@@ -111,8 +111,6 @@ static void hantro_job_finish(struct hantro_dev *vpu,
src->sequence = ctx->sequence_out++;
dst->sequence = ctx->sequence_cap++;
- v4l2_m2m_buf_copy_metadata(src, dst, true);
-
ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused);
if (ret)
result = VB2_BUF_STATE_ERROR;
@@ -153,11 +151,37 @@ void hantro_watchdog(struct work_struct *work)
}
}
+void hantro_prepare_run(struct hantro_ctx *ctx)
+{
+ struct vb2_v4l2_buffer *src_buf;
+
+ src_buf = hantro_get_src_buf(ctx);
+ v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+}
+
+void hantro_finish_run(struct hantro_ctx *ctx)
+{
+ struct vb2_v4l2_buffer *src_buf;
+
+ src_buf = hantro_get_src_buf(ctx);
+ v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+
+ /* Kick the watchdog. */
+ schedule_delayed_work(&ctx->dev->watchdog_work,
+ msecs_to_jiffies(2000));
+}
+
static void device_run(void *priv)
{
struct hantro_ctx *ctx = priv;
+ struct vb2_v4l2_buffer *src, *dst;
int ret;
+ src = hantro_get_src_buf(ctx);
+ dst = hantro_get_dst_buf(ctx);
+
ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks);
if (ret)
goto err_cancel_job;
@@ -165,6 +189,8 @@ static void device_run(void *priv)
if (ret < 0)
goto err_cancel_job;
+ v4l2_m2m_buf_copy_metadata(src, dst, true);
+
ctx->codec_ops->run(ctx);
return;
@@ -262,28 +288,74 @@ static const struct v4l2_ctrl_ops hantro_ctrl_ops = {
.s_ctrl = hantro_s_ctrl,
};
-static struct hantro_ctrl controls[] = {
+static const struct hantro_ctrl controls[] = {
{
- .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
.codec = HANTRO_JPEG_ENCODER,
.cfg = {
+ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
.min = 5,
.max = 100,
.step = 1,
.def = 50,
+ .ops = &hantro_ctrl_ops,
},
}, {
- .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
.codec = HANTRO_MPEG2_DECODER,
.cfg = {
- .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params),
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
},
}, {
- .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
.codec = HANTRO_MPEG2_DECODER,
.cfg = {
- .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization),
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
+ },
+ }, {
+ .codec = HANTRO_VP8_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER,
+ },
+ }, {
+ .codec = HANTRO_H264_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
},
+ }, {
+ .codec = HANTRO_H264_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
+ },
+ }, {
+ .codec = HANTRO_H264_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SPS,
+ },
+ }, {
+ .codec = HANTRO_H264_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PPS,
+ },
+ }, {
+ .codec = HANTRO_H264_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
+ },
+ }, {
+ .codec = HANTRO_H264_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE,
+ .min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
+ .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
+ .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
+ },
+ }, {
+ .codec = HANTRO_H264_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE,
+ .min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
+ .def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
+ .max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
+ },
+ }, {
},
};
@@ -298,22 +370,12 @@ static int hantro_ctrls_setup(struct hantro_dev *vpu,
for (i = 0; i < num_ctrls; i++) {
if (!(allowed_codecs & controls[i].codec))
continue;
- if (!controls[i].cfg.elem_size) {
- v4l2_ctrl_new_std(&ctx->ctrl_handler,
- &hantro_ctrl_ops,
- controls[i].id, controls[i].cfg.min,
- controls[i].cfg.max,
- controls[i].cfg.step,
- controls[i].cfg.def);
- } else {
- controls[i].cfg.id = controls[i].id;
- v4l2_ctrl_new_custom(&ctx->ctrl_handler,
- &controls[i].cfg, NULL);
- }
+ v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &controls[i].cfg, NULL);
if (ctx->ctrl_handler.error) {
vpu_err("Adding control (%d) failed %d\n",
- controls[i].id,
+ controls[i].cfg.id,
ctx->ctrl_handler.error);
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
return ctx->ctrl_handler.error;
@@ -419,6 +481,7 @@ static const struct v4l2_file_operations hantro_fops = {
static const struct of_device_id of_hantro_match[] = {
#ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP
{ .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
+ { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, },
{ .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
#endif
{ /* sentinel */ }
@@ -724,6 +787,7 @@ static int hantro_probe(struct platform_device *pdev)
dev_err(vpu->dev, "Could not set DMA coherent mask.\n");
return ret;
}
+ vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
for (i = 0; i < vpu->variant->num_irqs; i++) {
const char *irq_name = vpu->variant->irqs[i].name;
@@ -733,10 +797,8 @@ static int hantro_probe(struct platform_device *pdev)
continue;
irq = platform_get_irq_byname(vpu->pdev, irq_name);
- if (irq <= 0) {
- dev_err(vpu->dev, "Could not get %s IRQ.\n", irq_name);
+ if (irq <= 0)
return -ENXIO;
- }
ret = devm_request_irq(vpu->dev, irq,
vpu->variant->irqs[i].handler, 0,
diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c
new file mode 100644
index 000000000000..7ab534936843
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip RK3288 VPU codec driver
+ *
+ * Copyright (c) 2014 Rockchip Electronics Co., Ltd.
+ * Hertz Wong <hertz.wong@rock-chips.com>
+ * Herman Chen <herman.chen@rock-chips.com>
+ *
+ * Copyright (C) 2014 Google, Inc.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#include <linux/types.h>
+#include <linux/sort.h>
+
+#include <media/v4l2-mem2mem.h>
+
+#include "hantro_g1_regs.h"
+#include "hantro_hw.h"
+#include "hantro_v4l2.h"
+
+static void set_params(struct hantro_ctx *ctx)
+{
+ const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls;
+ const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode;
+ const struct v4l2_ctrl_h264_slice_params *slices = ctrls->slices;
+ const struct v4l2_ctrl_h264_sps *sps = ctrls->sps;
+ const struct v4l2_ctrl_h264_pps *pps = ctrls->pps;
+ struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx);
+ struct hantro_dev *vpu = ctx->dev;
+ u32 reg;
+
+ /* Decoder control register 0. */
+ reg = G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(0x0);
+ if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
+ reg |= G1_REG_DEC_CTRL0_SEQ_MBAFF_E;
+ reg |= G1_REG_DEC_CTRL0_PICORD_COUNT_E;
+ if (dec_param->nal_ref_idc)
+ reg |= G1_REG_DEC_CTRL0_WRITE_MVS_E;
+
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) &&
+ (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD ||
+ slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC))
+ reg |= G1_REG_DEC_CTRL0_PIC_INTERLACE_E;
+ if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
+ reg |= G1_REG_DEC_CTRL0_PIC_FIELDMODE_E;
+ if (!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD))
+ reg |= G1_REG_DEC_CTRL0_PIC_TOPFIELD_E;
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0);
+
+ /* Decoder control register 1. */
+ reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(sps->pic_width_in_mbs_minus1 + 1) |
+ G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(sps->pic_height_in_map_units_minus1 + 1) |
+ G1_REG_DEC_CTRL1_REF_FRAMES(sps->max_num_ref_frames);
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL1);
+
+ /* Decoder control register 2. */
+ reg = G1_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) |
+ G1_REG_DEC_CTRL2_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset);
+
+ /* always use the matrix sent from userspace */
+ reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E;
+
+ if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
+ reg |= G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E;
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2);
+
+ /* Decoder control register 3. */
+ reg = G1_REG_DEC_CTRL3_START_CODE_E |
+ G1_REG_DEC_CTRL3_INIT_QP(pps->pic_init_qp_minus26 + 26) |
+ G1_REG_DEC_CTRL3_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0));
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL3);
+
+ /* Decoder control register 4. */
+ reg = G1_REG_DEC_CTRL4_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) |
+ G1_REG_DEC_CTRL4_FRAMENUM(slices[0].frame_num) |
+ G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc);
+ if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE)
+ reg |= G1_REG_DEC_CTRL4_CABAC_E;
+ if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE)
+ reg |= G1_REG_DEC_CTRL4_DIR_8X8_INFER_E;
+ if (sps->chroma_format_idc == 0)
+ reg |= G1_REG_DEC_CTRL4_BLACKWHITE_E;
+ if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED)
+ reg |= G1_REG_DEC_CTRL4_WEIGHT_PRED_E;
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4);
+
+ /* Decoder control register 5. */
+ reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) |
+ G1_REG_DEC_CTRL5_IDR_PIC_ID(slices[0].idr_pic_id);
+ if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED)
+ reg |= G1_REG_DEC_CTRL5_CONST_INTRA_E;
+ if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT)
+ reg |= G1_REG_DEC_CTRL5_FILT_CTRL_PRES;
+ if (pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT)
+ reg |= G1_REG_DEC_CTRL5_RDPIC_CNT_PRES;
+ if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE)
+ reg |= G1_REG_DEC_CTRL5_8X8TRANS_FLAG_E;
+ if (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC)
+ reg |= G1_REG_DEC_CTRL5_IDR_PIC_E;
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL5);
+
+ /* Decoder control register 6. */
+ reg = G1_REG_DEC_CTRL6_PPS_ID(slices[0].pic_parameter_set_id) |
+ G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) |
+ G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) |
+ G1_REG_DEC_CTRL6_POC_LENGTH(slices[0].pic_order_cnt_bit_size);
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL6);
+
+ /* Error concealment register. */
+ vdpu_write_relaxed(vpu, 0, G1_REG_ERR_CONC);
+
+ /* Prediction filter tap register. */
+ vdpu_write_relaxed(vpu,
+ G1_REG_PRED_FLT_PRED_BC_TAP_0_0(1) |
+ G1_REG_PRED_FLT_PRED_BC_TAP_0_1(-5 & 0x3ff) |
+ G1_REG_PRED_FLT_PRED_BC_TAP_0_2(20),
+ G1_REG_PRED_FLT);
+
+ /* Reference picture buffer control register. */
+ vdpu_write_relaxed(vpu, 0, G1_REG_REF_BUF_CTRL);
+
+ /* Reference picture buffer control register 2. */
+ vdpu_write_relaxed(vpu, G1_REG_REF_BUF_CTRL2_APF_THRESHOLD(8),
+ G1_REG_REF_BUF_CTRL2);
+}
+
+static void set_ref(struct hantro_ctx *ctx)
+{
+ struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb;
+ const u8 *b0_reflist, *b1_reflist, *p_reflist;
+ struct hantro_dev *vpu = ctx->dev;
+ u32 dpb_longterm = 0;
+ u32 dpb_valid = 0;
+ int reg_num;
+ u32 reg;
+ int i;
+
+ /*
+ * Set up bit maps of valid and long term DPBs.
+ * NOTE: The bits are reversed, i.e. MSb is DPB 0.
+ */
+ for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) {
+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
+ dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i);
+
+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+ dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i);
+ }
+ vdpu_write_relaxed(vpu, dpb_valid << 16, G1_REG_VALID_REF);
+ vdpu_write_relaxed(vpu, dpb_longterm << 16, G1_REG_LT_REF);
+
+ /*
+ * Set up reference frame picture numbers.
+ *
+ * Each G1_REG_REF_PIC(x) register contains numbers of two
+ * subsequential reference pictures.
+ */
+ for (i = 0; i < HANTRO_H264_DPB_SIZE; i += 2) {
+ reg = 0;
+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+ reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].pic_num);
+ else
+ reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].frame_num);
+
+ if (dpb[i + 1].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+ reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].pic_num);
+ else
+ reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].frame_num);
+
+ vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(i / 2));
+ }
+
+ b0_reflist = ctx->h264_dec.reflists.b0;
+ b1_reflist = ctx->h264_dec.reflists.b1;
+ p_reflist = ctx->h264_dec.reflists.p;
+
+ /*
+ * Each G1_REG_BD_REF_PIC(x) register contains three entries
+ * of each forward and backward picture list.
+ */
+ reg_num = 0;
+ for (i = 0; i < 15; i += 3) {
+ reg = G1_REG_BD_REF_PIC_BINIT_RLIST_F0(b0_reflist[i]) |
+ G1_REG_BD_REF_PIC_BINIT_RLIST_F1(b0_reflist[i + 1]) |
+ G1_REG_BD_REF_PIC_BINIT_RLIST_F2(b0_reflist[i + 2]) |
+ G1_REG_BD_REF_PIC_BINIT_RLIST_B0(b1_reflist[i]) |
+ G1_REG_BD_REF_PIC_BINIT_RLIST_B1(b1_reflist[i + 1]) |
+ G1_REG_BD_REF_PIC_BINIT_RLIST_B2(b1_reflist[i + 2]);
+ vdpu_write_relaxed(vpu, reg, G1_REG_BD_REF_PIC(reg_num++));
+ }
+
+ /*
+ * G1_REG_BD_P_REF_PIC register contains last entries (index 15)
+ * of forward and backward reference picture lists and first 4 entries
+ * of P forward picture list.
+ */
+ reg = G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(b0_reflist[15]) |
+ G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(b1_reflist[15]) |
+ G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(p_reflist[0]) |
+ G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(p_reflist[1]) |
+ G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(p_reflist[2]) |
+ G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(p_reflist[3]);
+ vdpu_write_relaxed(vpu, reg, G1_REG_BD_P_REF_PIC);
+
+ /*
+ * Each G1_REG_FWD_PIC(x) register contains six consecutive
+ * entries of P forward picture list, starting from index 4.
+ */
+ reg_num = 0;
+ for (i = 4; i < HANTRO_H264_DPB_SIZE; i += 6) {
+ reg = G1_REG_FWD_PIC_PINIT_RLIST_F0(p_reflist[i]) |
+ G1_REG_FWD_PIC_PINIT_RLIST_F1(p_reflist[i + 1]) |
+ G1_REG_FWD_PIC_PINIT_RLIST_F2(p_reflist[i + 2]) |
+ G1_REG_FWD_PIC_PINIT_RLIST_F3(p_reflist[i + 3]) |
+ G1_REG_FWD_PIC_PINIT_RLIST_F4(p_reflist[i + 4]) |
+ G1_REG_FWD_PIC_PINIT_RLIST_F5(p_reflist[i + 5]);
+ vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(reg_num++));
+ }
+
+ /* Set up addresses of DPB buffers. */
+ for (i = 0; i < HANTRO_H264_DPB_SIZE; i++) {
+ struct vb2_buffer *buf = hantro_h264_get_ref_buf(ctx, i);
+
+ vdpu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(buf, 0),
+ G1_REG_ADDR_REF(i));
+ }
+}
+
+static void set_buffers(struct hantro_ctx *ctx)
+{
+ const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ struct hantro_dev *vpu = ctx->dev;
+ dma_addr_t src_dma, dst_dma;
+
+ src_buf = hantro_get_src_buf(ctx);
+ dst_buf = hantro_get_dst_buf(ctx);
+
+ /* Source (stream) buffer. */
+ src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ vdpu_write_relaxed(vpu, src_dma, G1_REG_ADDR_STR);
+
+ /* Destination (decoded frame) buffer. */
+ dst_dma = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+ vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST);
+
+ /* Higher profiles require DMV buffer appended to reference frames. */
+ if (ctrls->sps->profile_idc > 66) {
+ size_t pic_size = ctx->h264_dec.pic_size;
+ size_t mv_offset = round_up(pic_size, 8);
+
+ if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
+ mv_offset += 32 * H264_MB_WIDTH(ctx->dst_fmt.width);
+
+ vdpu_write_relaxed(vpu, dst_dma + mv_offset,
+ G1_REG_ADDR_DIR_MV);
+ }
+
+ /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */
+ vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_ADDR_QTABLE);
+}
+
+void hantro_g1_h264_dec_run(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ /* Prepare the H264 decoder context. */
+ if (hantro_h264_dec_prepare_run(ctx))
+ return;
+
+ /* Configure hardware registers. */
+ set_params(ctx);
+ set_ref(ctx);
+ set_buffers(ctx);
+
+ hantro_finish_run(ctx);
+
+ /* Start decoding! */
+ vdpu_write_relaxed(vpu,
+ G1_REG_CONFIG_DEC_AXI_RD_ID(0xffu) |
+ G1_REG_CONFIG_DEC_TIMEOUT_E |
+ G1_REG_CONFIG_DEC_OUT_ENDIAN |
+ G1_REG_CONFIG_DEC_STRENDIAN_E |
+ G1_REG_CONFIG_DEC_MAX_BURST(16) |
+ G1_REG_CONFIG_DEC_OUTSWAP32_E |
+ G1_REG_CONFIG_DEC_INSWAP32_E |
+ G1_REG_CONFIG_DEC_STRSWAP32_E |
+ G1_REG_CONFIG_DEC_CLK_GATE_E,
+ G1_REG_CONFIG);
+ vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT);
+}
diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
index e592c1b66375..80f0e94f8afa 100644
--- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
+++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
@@ -167,12 +167,11 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
const struct v4l2_mpeg2_picture *picture;
u32 reg;
- src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ src_buf = hantro_get_src_buf(ctx);
+ dst_buf = hantro_get_dst_buf(ctx);
/* Apply request controls if any */
- v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
- &ctx->ctrl_handler);
+ hantro_prepare_run(ctx);
slice_params = hantro_get_ctrl(ctx,
V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
@@ -248,12 +247,7 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
&dst_buf->vb2_buf,
sequence, picture, slice_params);
- /* Controls no longer in-use, we can complete them */
- v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
- &ctx->ctrl_handler);
-
- /* Kick the watchdog and start decoding */
- schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+ hantro_finish_run(ctx);
reg = G1_REG_DEC_E(1);
vdpu_write(vpu, reg, G1_SWREG(1));
diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c
new file mode 100644
index 000000000000..6d99c2be01cf
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VP8 codec driver
+ *
+ * Copyright (C) 2019 Rockchip Electronics Co., Ltd.
+ * ZhiChao Yu <zhichao.yu@rock-chips.com>
+ *
+ * Copyright (C) 2019 Google, Inc.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include <media/vp8-ctrls.h>
+
+#include "hantro_hw.h"
+#include "hantro.h"
+#include "hantro_g1_regs.h"
+
+/* DCT partition base address regs */
+static const struct hantro_reg vp8_dec_dct_base[8] = {
+ { G1_REG_ADDR_STR, 0, 0xffffffff },
+ { G1_REG_ADDR_REF(8), 0, 0xffffffff },
+ { G1_REG_ADDR_REF(9), 0, 0xffffffff },
+ { G1_REG_ADDR_REF(10), 0, 0xffffffff },
+ { G1_REG_ADDR_REF(11), 0, 0xffffffff },
+ { G1_REG_ADDR_REF(12), 0, 0xffffffff },
+ { G1_REG_ADDR_REF(14), 0, 0xffffffff },
+ { G1_REG_ADDR_REF(15), 0, 0xffffffff },
+};
+
+/* Loop filter level regs */
+static const struct hantro_reg vp8_dec_lf_level[4] = {
+ { G1_REG_REF_PIC(2), 18, 0x3f },
+ { G1_REG_REF_PIC(2), 12, 0x3f },
+ { G1_REG_REF_PIC(2), 6, 0x3f },
+ { G1_REG_REF_PIC(2), 0, 0x3f },
+};
+
+/* Macroblock loop filter level adjustment regs */
+static const struct hantro_reg vp8_dec_mb_adj[4] = {
+ { G1_REG_REF_PIC(0), 21, 0x7f },
+ { G1_REG_REF_PIC(0), 14, 0x7f },
+ { G1_REG_REF_PIC(0), 7, 0x7f },
+ { G1_REG_REF_PIC(0), 0, 0x7f },
+};
+
+/* Reference frame adjustment regs */
+static const struct hantro_reg vp8_dec_ref_adj[4] = {
+ { G1_REG_REF_PIC(1), 21, 0x7f },
+ { G1_REG_REF_PIC(1), 14, 0x7f },
+ { G1_REG_REF_PIC(1), 7, 0x7f },
+ { G1_REG_REF_PIC(1), 0, 0x7f },
+};
+
+/* Quantizer */
+static const struct hantro_reg vp8_dec_quant[4] = {
+ { G1_REG_REF_PIC(3), 11, 0x7ff },
+ { G1_REG_REF_PIC(3), 0, 0x7ff },
+ { G1_REG_BD_REF_PIC(4), 11, 0x7ff },
+ { G1_REG_BD_REF_PIC(4), 0, 0x7ff },
+};
+
+/* Quantizer delta regs */
+static const struct hantro_reg vp8_dec_quant_delta[5] = {
+ { G1_REG_REF_PIC(3), 27, 0x1f },
+ { G1_REG_REF_PIC(3), 22, 0x1f },
+ { G1_REG_BD_REF_PIC(4), 27, 0x1f },
+ { G1_REG_BD_REF_PIC(4), 22, 0x1f },
+ { G1_REG_BD_P_REF_PIC, 27, 0x1f },
+};
+
+/* DCT partition start bits regs */
+static const struct hantro_reg vp8_dec_dct_start_bits[8] = {
+ { G1_REG_DEC_CTRL2, 26, 0x3f }, { G1_REG_DEC_CTRL4, 26, 0x3f },
+ { G1_REG_DEC_CTRL4, 20, 0x3f }, { G1_REG_DEC_CTRL7, 24, 0x3f },
+ { G1_REG_DEC_CTRL7, 18, 0x3f }, { G1_REG_DEC_CTRL7, 12, 0x3f },
+ { G1_REG_DEC_CTRL7, 6, 0x3f }, { G1_REG_DEC_CTRL7, 0, 0x3f },
+};
+
+/* Precision filter tap regs */
+static const struct hantro_reg vp8_dec_pred_bc_tap[8][4] = {
+ {
+ { G1_REG_PRED_FLT, 22, 0x3ff },
+ { G1_REG_PRED_FLT, 12, 0x3ff },
+ { G1_REG_PRED_FLT, 2, 0x3ff },
+ { G1_REG_REF_PIC(4), 22, 0x3ff },
+ },
+ {
+ { G1_REG_REF_PIC(4), 12, 0x3ff },
+ { G1_REG_REF_PIC(4), 2, 0x3ff },
+ { G1_REG_REF_PIC(5), 22, 0x3ff },
+ { G1_REG_REF_PIC(5), 12, 0x3ff },
+ },
+ {
+ { G1_REG_REF_PIC(5), 2, 0x3ff },
+ { G1_REG_REF_PIC(6), 22, 0x3ff },
+ { G1_REG_REF_PIC(6), 12, 0x3ff },
+ { G1_REG_REF_PIC(6), 2, 0x3ff },
+ },
+ {
+ { G1_REG_REF_PIC(7), 22, 0x3ff },
+ { G1_REG_REF_PIC(7), 12, 0x3ff },
+ { G1_REG_REF_PIC(7), 2, 0x3ff },
+ { G1_REG_LT_REF, 22, 0x3ff },
+ },
+ {
+ { G1_REG_LT_REF, 12, 0x3ff },
+ { G1_REG_LT_REF, 2, 0x3ff },
+ { G1_REG_VALID_REF, 22, 0x3ff },
+ { G1_REG_VALID_REF, 12, 0x3ff },
+ },
+ {
+ { G1_REG_VALID_REF, 2, 0x3ff },
+ { G1_REG_BD_REF_PIC(0), 22, 0x3ff },
+ { G1_REG_BD_REF_PIC(0), 12, 0x3ff },
+ { G1_REG_BD_REF_PIC(0), 2, 0x3ff },
+ },
+ {
+ { G1_REG_BD_REF_PIC(1), 22, 0x3ff },
+ { G1_REG_BD_REF_PIC(1), 12, 0x3ff },
+ { G1_REG_BD_REF_PIC(1), 2, 0x3ff },
+ { G1_REG_BD_REF_PIC(2), 22, 0x3ff },
+ },
+ {
+ { G1_REG_BD_REF_PIC(2), 12, 0x3ff },
+ { G1_REG_BD_REF_PIC(2), 2, 0x3ff },
+ { G1_REG_BD_REF_PIC(3), 22, 0x3ff },
+ { G1_REG_BD_REF_PIC(3), 12, 0x3ff },
+ },
+};
+
+/*
+ * Set loop filters
+ */
+static void cfg_lf(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ const struct v4l2_vp8_segment_header *seg = &hdr->segment_header;
+ const struct v4l2_vp8_loopfilter_header *lf = &hdr->lf_header;
+ struct hantro_dev *vpu = ctx->dev;
+ unsigned int i;
+ u32 reg;
+
+ if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) {
+ hantro_reg_write(vpu, &vp8_dec_lf_level[0], lf->level);
+ } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) {
+ for (i = 0; i < 4; i++) {
+ u32 lf_level = clamp(lf->level + seg->lf_update[i],
+ 0, 63);
+
+ hantro_reg_write(vpu, &vp8_dec_lf_level[i], lf_level);
+ }
+ } else {
+ for (i = 0; i < 4; i++)
+ hantro_reg_write(vpu, &vp8_dec_lf_level[i],
+ seg->lf_update[i]);
+ }
+
+ reg = G1_REG_REF_PIC_FILT_SHARPNESS(lf->sharpness_level);
+ if (lf->flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE)
+ reg |= G1_REG_REF_PIC_FILT_TYPE_E;
+ vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(0));
+
+ if (lf->flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE) {
+ for (i = 0; i < 4; i++) {
+ hantro_reg_write(vpu, &vp8_dec_mb_adj[i],
+ lf->mb_mode_delta[i]);
+ hantro_reg_write(vpu, &vp8_dec_ref_adj[i],
+ lf->ref_frm_delta[i]);
+ }
+ }
+}
+
+/*
+ * Set quantization parameters
+ */
+static void cfg_qp(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ const struct v4l2_vp8_quantization_header *q = &hdr->quant_header;
+ const struct v4l2_vp8_segment_header *seg = &hdr->segment_header;
+ struct hantro_dev *vpu = ctx->dev;
+ unsigned int i;
+
+ if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) {
+ hantro_reg_write(vpu, &vp8_dec_quant[0], q->y_ac_qi);
+ } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) {
+ for (i = 0; i < 4; i++) {
+ u32 quant = clamp(q->y_ac_qi + seg->quant_update[i],
+ 0, 127);
+
+ hantro_reg_write(vpu, &vp8_dec_quant[i], quant);
+ }
+ } else {
+ for (i = 0; i < 4; i++)
+ hantro_reg_write(vpu, &vp8_dec_quant[i],
+ seg->quant_update[i]);
+ }
+
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[0], q->y_dc_delta);
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[1], q->y2_dc_delta);
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[2], q->y2_ac_delta);
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[3], q->uv_dc_delta);
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[4], q->uv_ac_delta);
+}
+
+/*
+ * set control partition and DCT partition regs
+ *
+ * VP8 frame stream data layout:
+ *
+ * first_part_size parttion_sizes[0]
+ * ^ ^
+ * src_dma | |
+ * ^ +--------+------+ +-----+-----+
+ * | | control part | | |
+ * +--------+----------------+------------------+-----------+-----+-----------+
+ * | tag 3B | extra 7B | hdr | mb_data | DCT sz | DCT part0 | ... | DCT partn |
+ * +--------+-----------------------------------+-----------+-----+-----------+
+ * | | | |
+ * v +----+---+ v
+ * mb_start | src_dma_end
+ * v
+ * DCT size part
+ * (num_dct-1)*3B
+ * Note:
+ * 1. only key-frames have extra 7-bytes
+ * 2. all offsets are base on src_dma
+ * 3. number of DCT parts is 1, 2, 4 or 8
+ * 4. the addresses set to the VPU must be 64-bits aligned
+ */
+static void cfg_parts(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *vb2_src;
+ u32 first_part_offset = VP8_FRAME_IS_KEY_FRAME(hdr) ? 10 : 3;
+ u32 mb_size, mb_offset_bytes, mb_offset_bits, mb_start_bits;
+ u32 dct_size_part_size, dct_part_offset;
+ struct hantro_reg reg;
+ dma_addr_t src_dma;
+ u32 dct_part_total_len = 0;
+ u32 count = 0;
+ unsigned int i;
+
+ vb2_src = hantro_get_src_buf(ctx);
+ src_dma = vb2_dma_contig_plane_dma_addr(&vb2_src->vb2_buf, 0);
+
+ /*
+ * Calculate control partition mb data info
+ * @first_part_header_bits: bits offset of mb data from first
+ * part start pos
+ * @mb_offset_bits: bits offset of mb data from src_dma
+ * base addr
+ * @mb_offset_byte: bytes offset of mb data from src_dma
+ * base addr
+ * @mb_start_bits: bits offset of mb data from mb data
+ * 64bits alignment addr
+ */
+ mb_offset_bits = first_part_offset * 8 +
+ hdr->first_part_header_bits + 8;
+ mb_offset_bytes = mb_offset_bits / 8;
+ mb_start_bits = mb_offset_bits -
+ (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) * 8;
+ mb_size = hdr->first_part_size -
+ (mb_offset_bytes - first_part_offset) +
+ (mb_offset_bytes & DEC_8190_ALIGN_MASK);
+
+ /* Macroblock data aligned base addr */
+ vdpu_write_relaxed(vpu, (mb_offset_bytes & (~DEC_8190_ALIGN_MASK))
+ + src_dma, G1_REG_ADDR_REF(13));
+
+ /* Macroblock data start bits */
+ reg.base = G1_REG_DEC_CTRL2;
+ reg.mask = 0x3f;
+ reg.shift = 18;
+ hantro_reg_write(vpu, &reg, mb_start_bits);
+
+ /* Macroblock aligned data length */
+ reg.base = G1_REG_DEC_CTRL6;
+ reg.mask = 0x3fffff;
+ reg.shift = 0;
+ hantro_reg_write(vpu, &reg, mb_size + 1);
+
+ /*
+ * Calculate DCT partition info
+ * @dct_size_part_size: Containing sizes of DCT part, every DCT part
+ * has 3 bytes to store its size, except the last
+ * DCT part
+ * @dct_part_offset: bytes offset of DCT parts from src_dma base addr
+ * @dct_part_total_len: total size of all DCT parts
+ */
+ dct_size_part_size = (hdr->num_dct_parts - 1) * 3;
+ dct_part_offset = first_part_offset + hdr->first_part_size;
+ for (i = 0; i < hdr->num_dct_parts; i++)
+ dct_part_total_len += hdr->dct_part_sizes[i];
+ dct_part_total_len += dct_size_part_size;
+ dct_part_total_len += (dct_part_offset & DEC_8190_ALIGN_MASK);
+
+ /* Number of DCT partitions */
+ reg.base = G1_REG_DEC_CTRL6;
+ reg.mask = 0xf;
+ reg.shift = 24;
+ hantro_reg_write(vpu, &reg, hdr->num_dct_parts - 1);
+
+ /* DCT partition length */
+ vdpu_write_relaxed(vpu,
+ G1_REG_DEC_CTRL3_STREAM_LEN(dct_part_total_len),
+ G1_REG_DEC_CTRL3);
+
+ /* DCT partitions base address */
+ for (i = 0; i < hdr->num_dct_parts; i++) {
+ u32 byte_offset = dct_part_offset + dct_size_part_size + count;
+ u32 base_addr = byte_offset + src_dma;
+
+ hantro_reg_write(vpu, &vp8_dec_dct_base[i],
+ base_addr & (~DEC_8190_ALIGN_MASK));
+
+ hantro_reg_write(vpu, &vp8_dec_dct_start_bits[i],
+ (byte_offset & DEC_8190_ALIGN_MASK) * 8);
+
+ count += hdr->dct_part_sizes[i];
+ }
+}
+
+/*
+ * prediction filter taps
+ * normal 6-tap filters
+ */
+static void cfg_tap(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_reg reg;
+ u32 val = 0;
+ int i, j;
+
+ reg.base = G1_REG_BD_REF_PIC(3);
+ reg.mask = 0xf;
+
+ if ((hdr->version & 0x03) != 0)
+ return; /* Tap filter not used. */
+
+ for (i = 0; i < 8; i++) {
+ val = (hantro_vp8_dec_mc_filter[i][0] << 2) |
+ hantro_vp8_dec_mc_filter[i][5];
+
+ for (j = 0; j < 4; j++)
+ hantro_reg_write(vpu, &vp8_dec_pred_bc_tap[i][j],
+ hantro_vp8_dec_mc_filter[i][j + 1]);
+
+ switch (i) {
+ case 2:
+ reg.shift = 8;
+ break;
+ case 4:
+ reg.shift = 4;
+ break;
+ case 6:
+ reg.shift = 0;
+ break;
+ default:
+ continue;
+ }
+
+ hantro_reg_write(vpu, &reg, val);
+ }
+}
+
+static void cfg_ref(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *vb2_dst;
+ dma_addr_t ref;
+
+ vb2_dst = hantro_get_dst_buf(ctx);
+
+ ref = hantro_get_ref(cap_q, hdr->last_frame_ts);
+ if (!ref)
+ ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0);
+ vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(0));
+
+ ref = hantro_get_ref(cap_q, hdr->golden_frame_ts);
+ WARN_ON(!ref && hdr->golden_frame_ts);
+ if (!ref)
+ ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0);
+ if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN)
+ ref |= G1_REG_ADDR_REF_TOPC_E;
+ vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(4));
+
+ ref = hantro_get_ref(cap_q, hdr->alt_frame_ts);
+ WARN_ON(!ref && hdr->alt_frame_ts);
+ if (!ref)
+ ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0);
+ if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT)
+ ref |= G1_REG_ADDR_REF_TOPC_E;
+ vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(5));
+}
+
+static void cfg_buffers(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ const struct v4l2_vp8_segment_header *seg = &hdr->segment_header;
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *vb2_dst;
+ dma_addr_t dst_dma;
+ u32 reg;
+
+ vb2_dst = hantro_get_dst_buf(ctx);
+
+ /* Set probability table buffer address */
+ vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma,
+ G1_REG_ADDR_QTABLE);
+
+ /* Set segment map address */
+ reg = G1_REG_FWD_PIC1_SEGMENT_BASE(ctx->vp8_dec.segment_map.dma);
+ if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED) {
+ reg |= G1_REG_FWD_PIC1_SEGMENT_E;
+ if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP)
+ reg |= G1_REG_FWD_PIC1_SEGMENT_UPD_E;
+ }
+ vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(0));
+
+ dst_dma = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0);
+ vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST);
+}
+
+void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
+{
+ const struct v4l2_ctrl_vp8_frame_header *hdr;
+ struct hantro_dev *vpu = ctx->dev;
+ size_t height = ctx->dst_fmt.height;
+ size_t width = ctx->dst_fmt.width;
+ u32 mb_width, mb_height;
+ u32 reg;
+
+ hantro_prepare_run(ctx);
+
+ hdr = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER);
+ if (WARN_ON(!hdr))
+ return;
+
+ /* Reset segment_map buffer in keyframe */
+ if (VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu)
+ memset(ctx->vp8_dec.segment_map.cpu, 0,
+ ctx->vp8_dec.segment_map.size);
+
+ hantro_vp8_prob_update(ctx, hdr);
+
+ reg = G1_REG_CONFIG_DEC_TIMEOUT_E |
+ G1_REG_CONFIG_DEC_STRENDIAN_E |
+ G1_REG_CONFIG_DEC_INSWAP32_E |
+ G1_REG_CONFIG_DEC_STRSWAP32_E |
+ G1_REG_CONFIG_DEC_OUTSWAP32_E |
+ G1_REG_CONFIG_DEC_CLK_GATE_E |
+ G1_REG_CONFIG_DEC_IN_ENDIAN |
+ G1_REG_CONFIG_DEC_OUT_ENDIAN |
+ G1_REG_CONFIG_DEC_MAX_BURST(16);
+ vdpu_write_relaxed(vpu, reg, G1_REG_CONFIG);
+
+ reg = G1_REG_DEC_CTRL0_DEC_MODE(10);
+ if (!VP8_FRAME_IS_KEY_FRAME(hdr))
+ reg |= G1_REG_DEC_CTRL0_PIC_INTER_E;
+ if (!(hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF))
+ reg |= G1_REG_DEC_CTRL0_SKIP_MODE;
+ if (hdr->lf_header.level == 0)
+ reg |= G1_REG_DEC_CTRL0_FILTERING_DIS;
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0);
+
+ /* Frame dimensions */
+ mb_width = VP8_MB_WIDTH(width);
+ mb_height = VP8_MB_HEIGHT(height);
+ reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(mb_width) |
+ G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(mb_height) |
+ G1_REG_DEC_CTRL1_PIC_MB_W_EXT(mb_width >> 9) |
+ G1_REG_DEC_CTRL1_PIC_MB_H_EXT(mb_height >> 8);
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL1);
+
+ /* Boolean decoder */
+ reg = G1_REG_DEC_CTRL2_BOOLEAN_RANGE(hdr->coder_state.range)
+ | G1_REG_DEC_CTRL2_BOOLEAN_VALUE(hdr->coder_state.value);
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2);
+
+ reg = 0;
+ if (hdr->version != 3)
+ reg |= G1_REG_DEC_CTRL4_VC1_HEIGHT_EXT;
+ if (hdr->version & 0x3)
+ reg |= G1_REG_DEC_CTRL4_BILIN_MC_E;
+ vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4);
+
+ cfg_lf(ctx, hdr);
+ cfg_qp(ctx, hdr);
+ cfg_parts(ctx, hdr);
+ cfg_tap(ctx, hdr);
+ cfg_ref(ctx, hdr);
+ cfg_buffers(ctx, hdr);
+
+ hantro_finish_run(ctx);
+
+ vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT);
+}
diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
index 0c1e3043dc7e..ecd34a7db190 100644
--- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
+++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
@@ -84,8 +84,10 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
struct hantro_jpeg_ctx jpeg_ctx;
u32 reg;
- src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ src_buf = hantro_get_src_buf(ctx);
+ dst_buf = hantro_get_dst_buf(ctx);
+
+ hantro_prepare_run(ctx);
memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
@@ -119,7 +121,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
| H1_REG_ENC_CTRL_ENC_MODE_JPEG
| H1_REG_ENC_PIC_INTRA
| H1_REG_ENC_CTRL_EN_BIT;
- /* Kick the watchdog and start encoding */
- schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+
+ hantro_finish_run(ctx);
+
vepu_write(vpu, reg, H1_REG_ENC_CTRL);
}
diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c
new file mode 100644
index 000000000000..0d758e0c0f99
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_h264.c
@@ -0,0 +1,646 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip RK3288 VPU codec driver
+ *
+ * Copyright (c) 2014 Rockchip Electronics Co., Ltd.
+ * Hertz Wong <hertz.wong@rock-chips.com>
+ * Herman Chen <herman.chen@rock-chips.com>
+ *
+ * Copyright (C) 2014 Google, Inc.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#include <linux/types.h>
+#include <linux/sort.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "hantro.h"
+#include "hantro_hw.h"
+
+/* Size with u32 units. */
+#define CABAC_INIT_BUFFER_SIZE (460 * 2)
+#define POC_BUFFER_SIZE 34
+#define SCALING_LIST_SIZE (6 * 16 + 6 * 64)
+
+#define POC_CMP(p0, p1) ((p0) < (p1) ? -1 : 1)
+
+/* Data structure describing auxiliary buffer format. */
+struct hantro_h264_dec_priv_tbl {
+ u32 cabac_table[CABAC_INIT_BUFFER_SIZE];
+ u32 poc[POC_BUFFER_SIZE];
+ u8 scaling_list[SCALING_LIST_SIZE];
+};
+
+/*
+ * Constant CABAC table.
+ * From drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_h264d.c
+ * in https://chromium.googlesource.com/chromiumos/third_party/kernel,
+ * chromeos-3.14 branch.
+ */
+static const u32 h264_cabac_table[] = {
+ 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07330000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x000b0137,
+ 0x0045ef7f, 0xf3660052, 0xf94aeb6b, 0xe57fe17f, 0xe87fee5f, 0xe57feb72,
+ 0xe27fef7b, 0xf473f07a, 0xf573f43f, 0xfe44f154, 0xf368fd46, 0xf85df65a,
+ 0xe27fff4a, 0xfa61f95b, 0xec7ffc38, 0xfb52f94c, 0xea7df95d, 0xf557fd4d,
+ 0xfb47fc3f, 0xfc44f454, 0xf93ef941, 0x083d0538, 0xfe420140, 0x003dfe4e,
+ 0x01320734, 0x0a23002c, 0x0b26012d, 0x002e052c, 0x1f110133, 0x07321c13,
+ 0x10210e3e, 0xf36cf164, 0xf365f35b, 0xf45ef658, 0xf054f656, 0xf953f357,
+ 0xed5e0146, 0x0048fb4a, 0x123bf866, 0xf164005f, 0xfc4b0248, 0xf54bfd47,
+ 0x0f2ef345, 0x003e0041, 0x1525f148, 0x09391036, 0x003e0c48, 0x18000f09,
+ 0x08190d12, 0x0f090d13, 0x0a250c12, 0x061d1421, 0x0f1e042d, 0x013a003e,
+ 0x073d0c26, 0x0b2d0f27, 0x0b2a0d2c, 0x102d0c29, 0x0a311e22, 0x122a0a37,
+ 0x1133112e, 0x00591aed, 0x16ef1aef, 0x1ee71cec, 0x21e925e5, 0x21e928e4,
+ 0x26ef21f5, 0x28f129fa, 0x26012911, 0x1efa1b03, 0x1a1625f0, 0x23fc26f8,
+ 0x26fd2503, 0x26052a00, 0x23102716, 0x0e301b25, 0x153c0c44, 0x0261fd47,
+ 0xfa2afb32, 0xfd36fe3e, 0x003a013f, 0xfe48ff4a, 0xf75bfb43, 0xfb1bfd27,
+ 0xfe2c002e, 0xf040f844, 0xf64efa4d, 0xf656f45c, 0xf137f63c, 0xfa3efc41,
+ 0xf449f84c, 0xf950f758, 0xef6ef561, 0xec54f54f, 0xfa49fc4a, 0xf356f360,
+ 0xf561ed75, 0xf84efb21, 0xfc30fe35, 0xfd3ef347, 0xf64ff456, 0xf35af261,
+ 0x0000fa5d, 0xfa54f84f, 0x0042ff47, 0x003efe3c, 0xfe3bfb4b, 0xfd3efc3a,
+ 0xf742ff4f, 0x00470344, 0x0a2cf93e, 0x0f240e28, 0x101b0c1d, 0x012c1424,
+ 0x1220052a, 0x01300a3e, 0x112e0940, 0xf468f561, 0xf060f958, 0xf855f955,
+ 0xf755f358, 0x0442fd4d, 0xfd4cfa4c, 0x0a3aff4c, 0xff53f963, 0xf25f025f,
+ 0x004cfb4a, 0x0046f54b, 0x01440041, 0xf249033e, 0x043eff44, 0xf34b0b37,
+ 0x05400c46, 0x0f060613, 0x07100c0e, 0x120d0d0b, 0x0d0f0f10, 0x0c170d17,
+ 0x0f140e1a, 0x0e2c1128, 0x112f1811, 0x15151916, 0x1f1b161d, 0x13230e32,
+ 0x0a39073f, 0xfe4dfc52, 0xfd5e0945, 0xf46d24dd, 0x24de20e6, 0x25e22ce0,
+ 0x22ee22f1, 0x28f121f9, 0x23fb2100, 0x2602210d, 0x17230d3a, 0x1dfd1a00,
+ 0x161e1ff9, 0x23f122fd, 0x220324ff, 0x2205200b, 0x2305220c, 0x270b1e1d,
+ 0x221a1d27, 0x13421f15, 0x1f1f1932, 0xef78ec70, 0xee72f555, 0xf15cf259,
+ 0xe647f151, 0xf2500044, 0xf246e838, 0xe944e832, 0xf54a17f3, 0x1af328f1,
+ 0x31f22c03, 0x2d062c22, 0x21361352, 0xfd4bff17, 0x0122012b, 0x0036fe37,
+ 0x003d0140, 0x0044f75c, 0xf26af361, 0xf15af45a, 0xee58f649, 0xf74ff256,
+ 0xf649f646, 0xf645fb42, 0xf740fb3a, 0x023b15f6, 0x18f51cf8, 0x1cff1d03,
+ 0x1d092314, 0x1d240e43, 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968,
+ 0xfa35ff36, 0x07331721, 0x17021500, 0x01090031, 0xdb760539, 0xf34ef541,
+ 0x013e0c31, 0xfc491132, 0x1240092b, 0x1d001a43, 0x105a0968, 0xd27fec68,
+ 0x0143f34e, 0xf541013e, 0xfa56ef5f, 0xfa3d092d, 0xfd45fa51, 0xf5600637,
+ 0x0743fb56, 0x0258003a, 0xfd4cf65e, 0x05360445, 0xfd510058, 0xf943fb4a,
+ 0xfc4afb50, 0xf948013a, 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948,
+ 0x0d29033e, 0x002dfc4e, 0xfd60e57e, 0xe462e765, 0xe943e452, 0xec5ef053,
+ 0xea6eeb5b, 0xee66f35d, 0xe37ff95c, 0xfb59f960, 0xf36cfd2e, 0xff41ff39,
+ 0xf75dfd4a, 0xf75cf857, 0xe97e0536, 0x063c063b, 0x0645ff30, 0x0044fc45,
+ 0xf858fe55, 0xfa4eff4b, 0xf94d0236, 0x0532fd44, 0x0132062a, 0xfc51013f,
+ 0xfc460043, 0x0239fe4c, 0x0b230440, 0x013d0b23, 0x12190c18, 0x0d1d0d24,
+ 0xf65df949, 0xfe490d2e, 0x0931f964, 0x09350235, 0x0535fe3d, 0x00380038,
+ 0xf33ffb3c, 0xff3e0439, 0xfa450439, 0x0e270433, 0x0d440340, 0x013d093f,
+ 0x07321027, 0x052c0434, 0x0b30fb3c, 0xff3b003b, 0x1621052c, 0x0e2bff4e,
+ 0x003c0945, 0x0b1c0228, 0x032c0031, 0x002e022c, 0x0233002f, 0x0427023e,
+ 0x062e0036, 0x0336023a, 0x043f0633, 0x06390735, 0x06340637, 0x0b2d0e24,
+ 0x0835ff52, 0x0737fd4e, 0x0f2e161f, 0xff541907, 0x1ef91c03, 0x1c042000,
+ 0x22ff1e06, 0x1e062009, 0x1f131a1b, 0x1a1e2514, 0x1c221146, 0x0143053b,
+ 0x0943101e, 0x12201223, 0x161d181f, 0x1726122b, 0x14290b3f, 0x093b0940,
+ 0xff5efe59, 0xf76cfa4c, 0xfe2c002d, 0x0034fd40, 0xfe3bfc46, 0xfc4bf852,
+ 0xef66f74d, 0x0318002a, 0x00300037, 0xfa3bf947, 0xf453f557, 0xe277013a,
+ 0xfd1dff24, 0x0126022b, 0xfa37003a, 0x0040fd4a, 0xf65a0046, 0xfc1d051f,
+ 0x072a013b, 0xfe3afd48, 0xfd51f561, 0x003a0805, 0x0a0e0e12, 0x0d1b0228,
+ 0x003afd46, 0xfa4ff855, 0x0000f36a, 0xf06af657, 0xeb72ee6e, 0xf262ea6e,
+ 0xeb6aee67, 0xeb6be96c, 0xe670f660, 0xf45ffb5b, 0xf75dea5e, 0xfb560943,
+ 0xfc50f655, 0xff46073c, 0x093a053d, 0x0c320f32, 0x12311136, 0x0a29072e,
+ 0xff330731, 0x08340929, 0x062f0237, 0x0d290a2c, 0x06320535, 0x0d31043f,
+ 0x0640fe45, 0xfe3b0646, 0x0a2c091f, 0x0c2b0335, 0x0e220a26, 0xfd340d28,
+ 0x1120072c, 0x07260d32, 0x0a391a2b, 0x0e0b0b0e, 0x090b120b, 0x150917fe,
+ 0x20f120f1, 0x22eb27e9, 0x2adf29e1, 0x2ee426f4, 0x151d2de8, 0x35d330e6,
+ 0x41d52bed, 0x27f61e09, 0x121a141b, 0x0039f252, 0xfb4bed61, 0xdd7d1b00,
+ 0x1c001ffc, 0x1b062208, 0x1e0a1816, 0x21131620, 0x1a1f1529, 0x1a2c172f,
+ 0x10410e47, 0x083c063f, 0x11411518, 0x17141a17, 0x1b201c17, 0x1c181728,
+ 0x18201c1d, 0x172a1339, 0x1635163d, 0x0b560c28, 0x0b330e3b, 0xfc4ff947,
+ 0xfb45f746, 0xf842f644, 0xed49f445, 0xf046f143, 0xec3eed46, 0xf042ea41,
+ 0xec3f09fe, 0x1af721f7, 0x27f929fe, 0x2d033109, 0x2d1b243b, 0xfa42f923,
+ 0xf92af82d, 0xfb30f438, 0xfa3cfb3e, 0xf842f84c, 0xfb55fa51, 0xf64df951,
+ 0xef50ee49, 0xfc4af653, 0xf747f743, 0xff3df842, 0xf242003b, 0x023b15f3,
+ 0x21f227f9, 0x2efe3302, 0x3c063d11, 0x37222a3e, 0x14f10236, 0x034a14f1,
+ 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331619, 0x22001000, 0xfe090429,
+ 0xe3760241, 0xfa47f34f, 0x05340932, 0xfd460a36, 0x1a221316, 0x28003902,
+ 0x29241a45, 0xd37ff165, 0xfc4cfa47, 0xf34f0534, 0x0645f35a, 0x0034082b,
+ 0xfe45fb52, 0xf660023b, 0x024bfd57, 0xfd640138, 0xfd4afa55, 0x003bfd51,
+ 0xf956fb5f, 0xff42ff4d, 0x0146fe56, 0xfb48003d, 0x0029003f, 0x003f003f,
+ 0xf7530456, 0x0061f948, 0x0d29033e, 0x0d0f0733, 0x0250d97f, 0xee5bef60,
+ 0xe651dd62, 0xe866e961, 0xe577e863, 0xeb6eee66, 0xdc7f0050, 0xfb59f95e,
+ 0xfc5c0027, 0x0041f154, 0xdd7ffe49, 0xf468f75b, 0xe17f0337, 0x07380737,
+ 0x083dfd35, 0x0044f94a, 0xf758f367, 0xf35bf759, 0xf25cf84c, 0xf457e96e,
+ 0xe869f64e, 0xec70ef63, 0xb27fba7f, 0xce7fd27f, 0xfc42fb4e, 0xfc47f848,
+ 0x023bff37, 0xf946fa4b, 0xf859de77, 0xfd4b2014, 0x1e16d47f, 0x0036fb3d,
+ 0x003aff3c, 0xfd3df843, 0xe754f24a, 0xfb410534, 0x0239003d, 0xf745f546,
+ 0x1237fc47, 0x003a073d, 0x09291219, 0x0920052b, 0x092f002c, 0x0033022e,
+ 0x1326fc42, 0x0f260c2a, 0x09220059, 0x042d0a1c, 0x0a1f21f5, 0x34d5120f,
+ 0x1c0023ea, 0x26e72200, 0x27ee20f4, 0x66a20000, 0x38f121fc, 0x1d0a25fb,
+ 0x33e327f7, 0x34de45c6, 0x43c12cfb, 0x200737e3, 0x20010000, 0x1b2421e7,
+ 0x22e224e4, 0x26e426e5, 0x22ee23f0, 0x22f220f8, 0x25fa2300, 0x1e0a1c12,
+ 0x1a191d29, 0x004b0248, 0x084d0e23, 0x121f1123, 0x151e112d, 0x142a122d,
+ 0x1b1a1036, 0x07421038, 0x0b490a43, 0xf674e970, 0xf147f93d, 0x0035fb42,
+ 0xf54df750, 0xf754f657, 0xde7feb65, 0xfd27fb35, 0xf93df54b, 0xf14def5b,
+ 0xe76be76f, 0xe47af54c, 0xf62cf634, 0xf639f73a, 0xf048f945, 0xfc45fb4a,
+ 0xf7560242, 0xf7220120, 0x0b1f0534, 0xfe37fe43, 0x0049f859, 0x03340704,
+ 0x0a081108, 0x10130325, 0xff3dfb49, 0xff46fc4e, 0x0000eb7e, 0xe97cec6e,
+ 0xe67ee77c, 0xef69e579, 0xe575ef66, 0xe675e574, 0xdf7af65f, 0xf264f85f,
+ 0xef6fe472, 0xfa59fe50, 0xfc52f755, 0xf851ff48, 0x05400143, 0x09380045,
+ 0x01450745, 0xf945fa43, 0xf04dfe40, 0x023dfa43, 0xfd400239, 0xfd41fd42,
+ 0x003e0933, 0xff42fe47, 0xfe4bff46, 0xf7480e3c, 0x1025002f, 0x12230b25,
+ 0x0c290a29, 0x02300c29, 0x0d29003b, 0x03321328, 0x03421232, 0x13fa12fa,
+ 0x0e001af4, 0x1ff021e7, 0x21ea25e4, 0x27e22ae2, 0x2fd62ddc, 0x31de29ef,
+ 0x200945b9, 0x3fc142c0, 0x4db636d9, 0x34dd29f6, 0x240028ff, 0x1e0e1c1a,
+ 0x17250c37, 0x0b4125df, 0x27dc28db, 0x26e22edf, 0x2ae228e8, 0x31e326f4,
+ 0x28f626fd, 0x2efb1f14, 0x1d1e192c, 0x0c300b31, 0x1a2d1616, 0x17161b15,
+ 0x21141a1c, 0x1e181b22, 0x122a1927, 0x12320c46, 0x15360e47, 0x0b531920,
+ 0x15311536, 0xfb55fa51, 0xf64df951, 0xef50ee49, 0xfc4af653, 0xf747f743,
+ 0xff3df842, 0xf242003b, 0x023b11f6, 0x20f32af7, 0x31fb3500, 0x4003440a,
+ 0x421b2f39, 0xfb470018, 0xff24fe2a, 0xfe34f739, 0xfa3ffc41, 0xfc43f952,
+ 0xfd51fd4c, 0xf948fa4e, 0xf448f244, 0xfd46fa4c, 0xfb42fb3e, 0x0039fc3d,
+ 0xf73c0136, 0x023a11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, 0x421b2f39,
+ 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331d10,
+ 0x19000e00, 0xf633fd3e, 0xe5631a10, 0xfc55e866, 0x05390639, 0xef490e39,
+ 0x1428140a, 0x1d003600, 0x252a0c61, 0xe07fea75, 0xfe4afc55, 0xe8660539,
+ 0xfa5df258, 0xfa2c0437, 0xf559f167, 0xeb741339, 0x143a0454, 0x0660013f,
+ 0xfb55f36a, 0x053f064b, 0xfd5aff65, 0x0337fc4f, 0xfe4bf461, 0xf932013c,
+ 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x0722f758,
+ 0xec7fdc7f, 0xef5bf25f, 0xe754e756, 0xf459ef5b, 0xe17ff24c, 0xee67f35a,
+ 0xdb7f0b50, 0x054c0254, 0x054efa37, 0x043df253, 0xdb7ffb4f, 0xf568f55b,
+ 0xe27f0041, 0xfe4f0048, 0xfc5cfa38, 0x0344f847, 0xf362fc56, 0xf458fb52,
+ 0xfd48fc43, 0xf848f059, 0xf745ff3b, 0x05420439, 0xfc47fe47, 0x023aff4a,
+ 0xfc2cff45, 0x003ef933, 0xfc2ffa2a, 0xfd29fa35, 0x084cf74e, 0xf5530934,
+ 0x0043fb5a, 0x0143f148, 0xfb4bf850, 0xeb53eb40, 0xf31fe740, 0xe35e094b,
+ 0x113ff84a, 0xfb23fe1b, 0x0d5b0341, 0xf945084d, 0xf642033e, 0xfd44ec51,
+ 0x001e0107, 0xfd17eb4a, 0x1042e97c, 0x11252cee, 0x32deea7f, 0x0427002a,
+ 0x07220b1d, 0x081f0625, 0x072a0328, 0x08210d2b, 0x0d24042f, 0x0337023a,
+ 0x063c082c, 0x0b2c0e2a, 0x07300438, 0x04340d25, 0x0931133a, 0x0a300c2d,
+ 0x00451421, 0x083f23ee, 0x21e71cfd, 0x180a1b00, 0x22f234d4, 0x27e81311,
+ 0x1f19241d, 0x1821220f, 0x1e141649, 0x1422131f, 0x1b2c1310, 0x0f240f24,
+ 0x151c1915, 0x1e141f0c, 0x1b10182a, 0x005d0e38, 0x0f391a26, 0xe87fe873,
+ 0xea52f73e, 0x0035003b, 0xf255f359, 0xf35ef55c, 0xe37feb64, 0xf239f443,
+ 0xf547f64d, 0xeb55f058, 0xe968f162, 0xdb7ff652, 0xf830f83d, 0xf842f946,
+ 0xf24bf64f, 0xf753f45c, 0xee6cfc4f, 0xea45f04b, 0xfe3a013a, 0xf34ef753,
+ 0xfc51f363, 0xf351fa26, 0xf33efa3a, 0xfe3bf049, 0xf64cf356, 0xf753f657,
+ 0x0000ea7f, 0xe77fe778, 0xe57fed72, 0xe975e776, 0xe675e871, 0xe476e178,
+ 0xdb7cf65e, 0xf166f663, 0xf36ace7f, 0xfb5c1139, 0xfb56f35e, 0xf45bfe4d,
+ 0x0047ff49, 0x0440f951, 0x05400f39, 0x01430044, 0xf6430144, 0x004d0240,
+ 0x0044fb4e, 0x0737053b, 0x02410e36, 0x0f2c053c, 0x0246fe4c, 0xee560c46,
+ 0x0540f446, 0x0b370538, 0x00450241, 0xfa4a0536, 0x0736fa4c, 0xf552fe4d,
+ 0xfe4d192a, 0x11f310f7, 0x11f41beb, 0x25e229d8, 0x2ad730d1, 0x27e02ed8,
+ 0x34cd2ed7, 0x34d92bed, 0x200b3dc9, 0x38d23ece, 0x51bd2dec, 0x23fe1c0f,
+ 0x22012701, 0x1e111426, 0x122d0f36, 0x004f24f0, 0x25f225ef, 0x2001220f,
+ 0x1d0f1819, 0x22161f10, 0x23121f1c, 0x2129241c, 0x1b2f153e, 0x121f131a,
+ 0x24181817, 0x1b10181e, 0x1f1d1629, 0x162a103c, 0x0f340e3c, 0x034ef07b,
+ 0x15351638, 0x193d1521, 0x1332113d, 0xfd4ef84a, 0xf748f648, 0xee4bf447,
+ 0xf53ffb46, 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc,
+ 0x21ff2107, 0x1f0c2517, 0x1f261440, 0xf747f925, 0xf82cf531, 0xf638f43b,
+ 0xf83ff743, 0xfa44f64f, 0xfd4ef84a, 0xf748f648, 0xee4bf447, 0xf53ffb46,
+ 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, 0x21ff2107,
+ 0x1f0c2517, 0x1f261440
+};
+
+/*
+ * NOTE: The scaling lists are in zig-zag order, apply inverse scanning process
+ * to get the values in matrix order. In addition, the hardware requires bytes
+ * swapped within each subsequent 4 bytes. Both arrays below include both
+ * transformations.
+ */
+static const u32 zig_zag_4x4[] = {
+ 3, 2, 7, 11, 6, 1, 0, 5, 10, 15, 14, 9, 4, 8, 13, 12
+};
+
+static const u32 zig_zag_8x8[] = {
+ 3, 2, 11, 19, 10, 1, 0, 9, 18, 27, 35, 26, 17, 8, 7, 6,
+ 15, 16, 25, 34, 43, 51, 42, 33, 24, 23, 14, 5, 4, 13, 22, 31,
+ 32, 41, 50, 59, 58, 49, 40, 39, 30, 21, 12, 20, 29, 38, 47, 48,
+ 57, 56, 55, 46, 37, 28, 36, 45, 54, 63, 62, 53, 44, 52, 61, 60
+};
+
+static void
+reorder_scaling_list(struct hantro_ctx *ctx)
+{
+ const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls;
+ const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling;
+ const size_t num_list_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4);
+ const size_t list_len_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4[0]);
+ const size_t num_list_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8);
+ const size_t list_len_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8[0]);
+ struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu;
+ u8 *dst = tbl->scaling_list;
+ const u8 *src;
+ int i, j;
+
+ BUILD_BUG_ON(ARRAY_SIZE(zig_zag_4x4) != list_len_4x4);
+ BUILD_BUG_ON(ARRAY_SIZE(zig_zag_8x8) != list_len_8x8);
+ BUILD_BUG_ON(ARRAY_SIZE(tbl->scaling_list) !=
+ num_list_4x4 * list_len_4x4 +
+ num_list_8x8 * list_len_8x8);
+
+ src = &scaling->scaling_list_4x4[0][0];
+ for (i = 0; i < num_list_4x4; ++i) {
+ for (j = 0; j < list_len_4x4; ++j)
+ dst[zig_zag_4x4[j]] = src[j];
+ src += list_len_4x4;
+ dst += list_len_4x4;
+ }
+
+ src = &scaling->scaling_list_8x8[0][0];
+ for (i = 0; i < num_list_8x8; ++i) {
+ for (j = 0; j < list_len_8x8; ++j)
+ dst[zig_zag_8x8[j]] = src[j];
+ src += list_len_8x8;
+ dst += list_len_8x8;
+ }
+}
+
+static void prepare_table(struct hantro_ctx *ctx)
+{
+ const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls;
+ const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode;
+ struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu;
+ const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb;
+ int i;
+
+ for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) {
+ tbl->poc[i * 2] = dpb[i].top_field_order_cnt;
+ tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt;
+ }
+
+ tbl->poc[32] = dec_param->top_field_order_cnt;
+ tbl->poc[33] = dec_param->bottom_field_order_cnt;
+
+ reorder_scaling_list(ctx);
+}
+
+struct hantro_h264_reflist_builder {
+ const struct v4l2_h264_dpb_entry *dpb;
+ s32 pocs[HANTRO_H264_DPB_SIZE];
+ u8 unordered_reflist[HANTRO_H264_DPB_SIZE];
+ s32 curpoc;
+ u8 num_valid;
+};
+
+static s32 get_poc(enum v4l2_field field, s32 top_field_order_cnt,
+ s32 bottom_field_order_cnt)
+{
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ return top_field_order_cnt;
+ case V4L2_FIELD_BOTTOM:
+ return bottom_field_order_cnt;
+ default:
+ break;
+ }
+
+ return min(top_field_order_cnt, bottom_field_order_cnt);
+}
+
+static void
+init_reflist_builder(struct hantro_ctx *ctx,
+ struct hantro_h264_reflist_builder *b)
+{
+ const struct v4l2_ctrl_h264_decode_params *dec_param;
+ struct vb2_v4l2_buffer *buf = hantro_get_dst_buf(ctx);
+ const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb;
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ unsigned int i;
+
+ dec_param = ctx->h264_dec.ctrls.decode;
+
+ memset(b, 0, sizeof(*b));
+ b->dpb = dpb;
+ b->curpoc = get_poc(buf->field, dec_param->top_field_order_cnt,
+ dec_param->bottom_field_order_cnt);
+
+ for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) {
+ int buf_idx;
+
+ if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+ continue;
+
+ buf_idx = vb2_find_timestamp(cap_q, dpb[i].reference_ts, 0);
+ if (buf_idx < 0)
+ continue;
+
+ buf = to_vb2_v4l2_buffer(vb2_get_buffer(cap_q, buf_idx));
+ b->pocs[i] = get_poc(buf->field, dpb[i].top_field_order_cnt,
+ dpb[i].bottom_field_order_cnt);
+ b->unordered_reflist[b->num_valid] = i;
+ b->num_valid++;
+ }
+
+ for (i = b->num_valid; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++)
+ b->unordered_reflist[i] = i;
+}
+
+static int p_ref_list_cmp(const void *ptra, const void *ptrb, const void *data)
+{
+ const struct hantro_h264_reflist_builder *builder = data;
+ const struct v4l2_h264_dpb_entry *a, *b;
+ u8 idxa, idxb;
+
+ idxa = *((u8 *)ptra);
+ idxb = *((u8 *)ptrb);
+ a = &builder->dpb[idxa];
+ b = &builder->dpb[idxb];
+
+ if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) !=
+ (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) {
+ /* Short term pics firt. */
+ if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
+ return -1;
+ else
+ return 1;
+ }
+
+ /*
+ * Short term pics in descending pic num order, long term ones in
+ * ascending order.
+ */
+ if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
+ return b->frame_num - a->frame_num;
+
+ return a->pic_num - b->pic_num;
+}
+
+static int b0_ref_list_cmp(const void *ptra, const void *ptrb, const void *data)
+{
+ const struct hantro_h264_reflist_builder *builder = data;
+ const struct v4l2_h264_dpb_entry *a, *b;
+ s32 poca, pocb;
+ u8 idxa, idxb;
+
+ idxa = *((u8 *)ptra);
+ idxb = *((u8 *)ptrb);
+ a = &builder->dpb[idxa];
+ b = &builder->dpb[idxb];
+
+ if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) !=
+ (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) {
+ /* Short term pics firt. */
+ if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
+ return -1;
+ else
+ return 1;
+ }
+
+ /* Long term pics in ascending pic num order. */
+ if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+ return a->pic_num - b->pic_num;
+
+ poca = builder->pocs[idxa];
+ pocb = builder->pocs[idxb];
+
+ /*
+ * Short term pics with POC < cur POC first in POC descending order
+ * followed by short term pics with POC > cur POC in POC ascending
+ * order.
+ */
+ if ((poca < builder->curpoc) != (pocb < builder->curpoc))
+ return POC_CMP(poca, pocb);
+ else if (poca < builder->curpoc)
+ return POC_CMP(pocb, poca);
+
+ return POC_CMP(poca, pocb);
+}
+
+static int b1_ref_list_cmp(const void *ptra, const void *ptrb, const void *data)
+{
+ const struct hantro_h264_reflist_builder *builder = data;
+ const struct v4l2_h264_dpb_entry *a, *b;
+ s32 poca, pocb;
+ u8 idxa, idxb;
+
+ idxa = *((u8 *)ptra);
+ idxb = *((u8 *)ptrb);
+ a = &builder->dpb[idxa];
+ b = &builder->dpb[idxb];
+
+ if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) !=
+ (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) {
+ /* Short term pics firt. */
+ if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
+ return -1;
+ else
+ return 1;
+ }
+
+ /* Long term pics in ascending pic num order. */
+ if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+ return a->pic_num - b->pic_num;
+
+ poca = builder->pocs[idxa];
+ pocb = builder->pocs[idxb];
+
+ /*
+ * Short term pics with POC > cur POC first in POC ascending order
+ * followed by short term pics with POC > cur POC in POC descending
+ * order.
+ */
+ if ((poca < builder->curpoc) != (pocb < builder->curpoc))
+ return POC_CMP(pocb, poca);
+ else if (poca < builder->curpoc)
+ return POC_CMP(pocb, poca);
+
+ return POC_CMP(poca, pocb);
+}
+
+static void
+build_p_ref_list(const struct hantro_h264_reflist_builder *builder,
+ u8 *reflist)
+{
+ memcpy(reflist, builder->unordered_reflist,
+ sizeof(builder->unordered_reflist));
+ sort_r(reflist, builder->num_valid, sizeof(*reflist),
+ p_ref_list_cmp, NULL, builder);
+}
+
+static void
+build_b_ref_lists(const struct hantro_h264_reflist_builder *builder,
+ u8 *b0_reflist, u8 *b1_reflist)
+{
+ memcpy(b0_reflist, builder->unordered_reflist,
+ sizeof(builder->unordered_reflist));
+ sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist),
+ b0_ref_list_cmp, NULL, builder);
+
+ memcpy(b1_reflist, builder->unordered_reflist,
+ sizeof(builder->unordered_reflist));
+ sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist),
+ b1_ref_list_cmp, NULL, builder);
+
+ if (builder->num_valid > 1 &&
+ !memcmp(b1_reflist, b0_reflist, builder->num_valid))
+ swap(b1_reflist[0], b1_reflist[1]);
+}
+
+static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a,
+ const struct v4l2_h264_dpb_entry *b)
+{
+ return a->top_field_order_cnt == b->top_field_order_cnt &&
+ a->bottom_field_order_cnt == b->bottom_field_order_cnt;
+}
+
+static void update_dpb(struct hantro_ctx *ctx)
+{
+ const struct v4l2_ctrl_h264_decode_params *dec_param;
+ DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, };
+ DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, };
+ unsigned int i, j;
+
+ dec_param = ctx->h264_dec.ctrls.decode;
+
+ /* Disable all entries by default. */
+ for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++)
+ ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE;
+
+ /* Try to match new DPB entries with existing ones by their POCs. */
+ for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) {
+ const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i];
+
+ if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+ continue;
+
+ /*
+ * To cut off some comparisons, iterate only on target DPB
+ * entries which are not used yet.
+ */
+ for_each_clear_bit(j, used, ARRAY_SIZE(ctx->h264_dec.dpb)) {
+ struct v4l2_h264_dpb_entry *cdpb;
+
+ cdpb = &ctx->h264_dec.dpb[j];
+ if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE ||
+ !dpb_entry_match(cdpb, ndpb))
+ continue;
+
+ *cdpb = *ndpb;
+ set_bit(j, used);
+ break;
+ }
+
+ if (j == ARRAY_SIZE(ctx->h264_dec.dpb))
+ set_bit(i, new);
+ }
+
+ /* For entries that could not be matched, use remaining free slots. */
+ for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) {
+ const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i];
+ struct v4l2_h264_dpb_entry *cdpb;
+
+ /*
+ * Both arrays are of the same sizes, so there is no way
+ * we can end up with no space in target array, unless
+ * something is buggy.
+ */
+ j = find_first_zero_bit(used, ARRAY_SIZE(ctx->h264_dec.dpb));
+ if (WARN_ON(j >= ARRAY_SIZE(ctx->h264_dec.dpb)))
+ return;
+
+ cdpb = &ctx->h264_dec.dpb[j];
+ *cdpb = *ndpb;
+ set_bit(j, used);
+ }
+}
+
+struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx,
+ unsigned int dpb_idx)
+{
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb;
+ struct vb2_buffer *buf;
+ int buf_idx = -1;
+
+ if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
+ buf_idx = vb2_find_timestamp(cap_q,
+ dpb[dpb_idx].reference_ts, 0);
+
+ if (buf_idx >= 0) {
+ buf = vb2_get_buffer(cap_q, buf_idx);
+ } else {
+ struct vb2_v4l2_buffer *dst_buf;
+
+ /*
+ * If a DPB entry is unused or invalid, address of current
+ * destination buffer is returned.
+ */
+ dst_buf = hantro_get_dst_buf(ctx);
+ buf = &dst_buf->vb2_buf;
+ }
+
+ return buf;
+}
+
+int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx)
+{
+ struct hantro_h264_dec_hw_ctx *h264_ctx = &ctx->h264_dec;
+ struct hantro_h264_dec_ctrls *ctrls = &h264_ctx->ctrls;
+ struct hantro_h264_reflist_builder reflist_builder;
+
+ hantro_prepare_run(ctx);
+
+ ctrls->scaling =
+ hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX);
+ if (WARN_ON(!ctrls->scaling))
+ return -EINVAL;
+
+ ctrls->decode =
+ hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS);
+ if (WARN_ON(!ctrls->decode))
+ return -EINVAL;
+
+ ctrls->slices =
+ hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS);
+ if (WARN_ON(!ctrls->slices))
+ return -EINVAL;
+
+ ctrls->sps =
+ hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SPS);
+ if (WARN_ON(!ctrls->sps))
+ return -EINVAL;
+
+ ctrls->pps =
+ hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_PPS);
+ if (WARN_ON(!ctrls->pps))
+ return -EINVAL;
+
+ /* Update the DPB with new refs. */
+ update_dpb(ctx);
+
+ /* Prepare data in memory. */
+ prepare_table(ctx);
+
+ /* Build the P/B{0,1} ref lists. */
+ init_reflist_builder(ctx, &reflist_builder);
+ build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
+ build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
+ h264_ctx->reflists.b1);
+ return 0;
+}
+
+void hantro_h264_dec_exit(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_h264_dec_hw_ctx *h264_dec = &ctx->h264_dec;
+ struct hantro_aux_buf *priv = &h264_dec->priv;
+
+ dma_free_coherent(vpu->dev, priv->size, priv->cpu, priv->dma);
+}
+
+int hantro_h264_dec_init(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_h264_dec_hw_ctx *h264_dec = &ctx->h264_dec;
+ struct hantro_aux_buf *priv = &h264_dec->priv;
+ struct hantro_h264_dec_priv_tbl *tbl;
+ struct v4l2_pix_format_mplane pix_mp;
+
+ priv->cpu = dma_alloc_coherent(vpu->dev, sizeof(*tbl), &priv->dma,
+ GFP_KERNEL);
+ if (!priv->cpu)
+ return -ENOMEM;
+
+ priv->size = sizeof(*tbl);
+ tbl = priv->cpu;
+ memcpy(tbl->cabac_table, h264_cabac_table, sizeof(tbl->cabac_table));
+
+ v4l2_fill_pixfmt_mp(&pix_mp, ctx->dst_fmt.pixelformat,
+ ctx->dst_fmt.width, ctx->dst_fmt.height);
+ h264_dec->pic_size = pix_mp.plane_fmt[0].sizeimage;
+
+ return 0;
+}
diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h
index 3c361c2e9b88..2fab655bf098 100644
--- a/drivers/staging/media/hantro/hantro_hw.h
+++ b/drivers/staging/media/hantro/hantro_hw.h
@@ -11,9 +11,13 @@
#include <linux/interrupt.h>
#include <linux/v4l2-controls.h>
+#include <media/h264-ctrls.h>
#include <media/mpeg2-ctrls.h>
+#include <media/vp8-ctrls.h>
#include <media/videobuf2-core.h>
+#define DEC_8190_ALIGN_MASK 0x07U
+
struct hantro_dev;
struct hantro_ctx;
struct hantro_buf;
@@ -39,6 +43,54 @@ struct hantro_jpeg_enc_hw_ctx {
struct hantro_aux_buf bounce_buffer;
};
+/* Max. number of entries in the DPB (HW limitation). */
+#define HANTRO_H264_DPB_SIZE 16
+
+/**
+ * struct hantro_h264_dec_ctrls
+ * @decode: Decode params
+ * @scaling: Scaling info
+ * @slice: Slice params
+ * @sps: SPS info
+ * @pps: PPS info
+ */
+struct hantro_h264_dec_ctrls {
+ const struct v4l2_ctrl_h264_decode_params *decode;
+ const struct v4l2_ctrl_h264_scaling_matrix *scaling;
+ const struct v4l2_ctrl_h264_slice_params *slices;
+ const struct v4l2_ctrl_h264_sps *sps;
+ const struct v4l2_ctrl_h264_pps *pps;
+};
+
+/**
+ * struct hantro_h264_dec_reflists
+ * @p: P reflist
+ * @b0: B0 reflist
+ * @b1: B1 reflist
+ */
+struct hantro_h264_dec_reflists {
+ u8 p[HANTRO_H264_DPB_SIZE];
+ u8 b0[HANTRO_H264_DPB_SIZE];
+ u8 b1[HANTRO_H264_DPB_SIZE];
+};
+
+/**
+ * struct hantro_h264_dec_hw_ctx
+ * @priv: Private auxiliary buffer for hardware.
+ * @dpb: DPB
+ * @reflists: P/B0/B1 reflists
+ * @ctrls: V4L2 controls attached to a run
+ * @pic_size: Size in bytes of decoded picture, this is needed
+ * to pass the location of motion vectors.
+ */
+struct hantro_h264_dec_hw_ctx {
+ struct hantro_aux_buf priv;
+ struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE];
+ struct hantro_h264_dec_reflists reflists;
+ struct hantro_h264_dec_ctrls ctrls;
+ size_t pic_size;
+};
+
/**
* struct hantro_mpeg2_dec_hw_ctx
* @qtable: Quantization table
@@ -48,6 +100,16 @@ struct hantro_mpeg2_dec_hw_ctx {
};
/**
+ * struct hantro_vp8d_hw_ctx
+ * @segment_map: Segment map buffer.
+ * @prob_tbl: Probability table buffer.
+ */
+struct hantro_vp8_dec_hw_ctx {
+ struct hantro_aux_buf segment_map;
+ struct hantro_aux_buf prob_tbl;
+};
+
+/**
* struct hantro_codec_ops - codec mode specific operations
*
* @init: If needed, can be used for initialization.
@@ -82,16 +144,27 @@ extern const struct hantro_variant rk3399_vpu_variant;
extern const struct hantro_variant rk3328_vpu_variant;
extern const struct hantro_variant rk3288_vpu_variant;
+extern const u32 hantro_vp8_dec_mc_filter[8][6];
+
void hantro_watchdog(struct work_struct *work);
void hantro_run(struct hantro_ctx *ctx);
void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused,
enum vb2_buffer_state result);
+void hantro_prepare_run(struct hantro_ctx *ctx);
+void hantro_finish_run(struct hantro_ctx *ctx);
void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx);
void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx);
int hantro_jpeg_enc_init(struct hantro_ctx *ctx);
void hantro_jpeg_enc_exit(struct hantro_ctx *ctx);
+struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx,
+ unsigned int dpb_idx);
+int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx);
+void hantro_g1_h264_dec_run(struct hantro_ctx *ctx);
+int hantro_h264_dec_init(struct hantro_ctx *ctx);
+void hantro_h264_dec_exit(struct hantro_ctx *ctx);
+
void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx);
void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx);
void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
@@ -99,4 +172,11 @@ void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
int hantro_mpeg2_dec_init(struct hantro_ctx *ctx);
void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx);
+void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx);
+void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx);
+int hantro_vp8_dec_init(struct hantro_ctx *ctx);
+void hantro_vp8_dec_exit(struct hantro_ctx *ctx);
+void hantro_vp8_prob_update(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr);
+
#endif /* HANTRO_HW_H_ */
diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c
index 68f45ee66821..3dae52abb96c 100644
--- a/drivers/staging/media/hantro/hantro_v4l2.c
+++ b/drivers/staging/media/hantro/hantro_v4l2.c
@@ -239,6 +239,15 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f,
/* Fill remaining fields */
v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width,
pix_mp->height);
+ /*
+ * The H264 decoder needs extra space on the output buffers
+ * to store motion vectors. This is needed for reference
+ * frames.
+ */
+ if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE)
+ pix_mp->plane_fmt[0].sizeimage +=
+ 128 * DIV_ROUND_UP(pix_mp->width, 16) *
+ DIV_ROUND_UP(pix_mp->height, 16);
} else if (!pix_mp->plane_fmt[0].sizeimage) {
/*
* For coded formats the application can specify
@@ -344,6 +353,8 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc)
ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false;
break;
case V4L2_PIX_FMT_MPEG2_SLICE:
+ case V4L2_PIX_FMT_VP8_FRAME:
+ case V4L2_PIX_FMT_H264_SLICE:
ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true;
break;
default:
diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/staging/media/hantro/hantro_vp8.c
new file mode 100644
index 000000000000..0e02d147b189
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_vp8.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include "hantro.h"
+
+/*
+ * probs table with packed
+ */
+struct vp8_prob_tbl_packed {
+ u8 prob_mb_skip_false;
+ u8 prob_intra;
+ u8 prob_ref_last;
+ u8 prob_ref_golden;
+ u8 prob_segment[3];
+ u8 padding0;
+
+ u8 prob_luma_16x16_pred_mode[4];
+ u8 prob_chroma_pred_mode[3];
+ u8 padding1;
+
+ /* mv prob */
+ u8 prob_mv_context[2][19];
+ u8 padding2[2];
+
+ /* coeff probs */
+ u8 prob_coeffs[4][8][3][11];
+ u8 padding3[96];
+};
+
+/*
+ * filter taps taken to 7-bit precision,
+ * reference RFC6386#Page-16, filters[8][6]
+ */
+const u32 hantro_vp8_dec_mc_filter[8][6] = {
+ { 0, 0, 128, 0, 0, 0 },
+ { 0, -6, 123, 12, -1, 0 },
+ { 2, -11, 108, 36, -8, 1 },
+ { 0, -9, 93, 50, -6, 0 },
+ { 3, -16, 77, 77, -16, 3 },
+ { 0, -6, 50, 93, -9, 0 },
+ { 1, -8, 36, 108, -11, 2 },
+ { 0, -1, 12, 123, -6, 0 }
+};
+
+void hantro_vp8_prob_update(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ const struct v4l2_vp8_entropy_header *entropy = &hdr->entropy_header;
+ u32 i, j, k;
+ u8 *dst;
+
+ /* first probs */
+ dst = ctx->vp8_dec.prob_tbl.cpu;
+
+ dst[0] = hdr->prob_skip_false;
+ dst[1] = hdr->prob_intra;
+ dst[2] = hdr->prob_last;
+ dst[3] = hdr->prob_gf;
+ dst[4] = hdr->segment_header.segment_probs[0];
+ dst[5] = hdr->segment_header.segment_probs[1];
+ dst[6] = hdr->segment_header.segment_probs[2];
+ dst[7] = 0;
+
+ dst += 8;
+ dst[0] = entropy->y_mode_probs[0];
+ dst[1] = entropy->y_mode_probs[1];
+ dst[2] = entropy->y_mode_probs[2];
+ dst[3] = entropy->y_mode_probs[3];
+ dst[4] = entropy->uv_mode_probs[0];
+ dst[5] = entropy->uv_mode_probs[1];
+ dst[6] = entropy->uv_mode_probs[2];
+ dst[7] = 0; /*unused */
+
+ /* mv probs */
+ dst += 8;
+ dst[0] = entropy->mv_probs[0][0]; /* is short */
+ dst[1] = entropy->mv_probs[1][0];
+ dst[2] = entropy->mv_probs[0][1]; /* sign */
+ dst[3] = entropy->mv_probs[1][1];
+ dst[4] = entropy->mv_probs[0][8 + 9];
+ dst[5] = entropy->mv_probs[0][9 + 9];
+ dst[6] = entropy->mv_probs[1][8 + 9];
+ dst[7] = entropy->mv_probs[1][9 + 9];
+ dst += 8;
+ for (i = 0; i < 2; ++i) {
+ for (j = 0; j < 8; j += 4) {
+ dst[0] = entropy->mv_probs[i][j + 9 + 0];
+ dst[1] = entropy->mv_probs[i][j + 9 + 1];
+ dst[2] = entropy->mv_probs[i][j + 9 + 2];
+ dst[3] = entropy->mv_probs[i][j + 9 + 3];
+ dst += 4;
+ }
+ }
+ for (i = 0; i < 2; ++i) {
+ dst[0] = entropy->mv_probs[i][0 + 2];
+ dst[1] = entropy->mv_probs[i][1 + 2];
+ dst[2] = entropy->mv_probs[i][2 + 2];
+ dst[3] = entropy->mv_probs[i][3 + 2];
+ dst[4] = entropy->mv_probs[i][4 + 2];
+ dst[5] = entropy->mv_probs[i][5 + 2];
+ dst[6] = entropy->mv_probs[i][6 + 2];
+ dst[7] = 0; /*unused */
+ dst += 8;
+ }
+
+ /* coeff probs (header part) */
+ dst = ctx->vp8_dec.prob_tbl.cpu;
+ dst += (8 * 7);
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 8; ++j) {
+ for (k = 0; k < 3; ++k) {
+ dst[0] = entropy->coeff_probs[i][j][k][0];
+ dst[1] = entropy->coeff_probs[i][j][k][1];
+ dst[2] = entropy->coeff_probs[i][j][k][2];
+ dst[3] = entropy->coeff_probs[i][j][k][3];
+ dst += 4;
+ }
+ }
+ }
+
+ /* coeff probs (footer part) */
+ dst = ctx->vp8_dec.prob_tbl.cpu;
+ dst += (8 * 55);
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 8; ++j) {
+ for (k = 0; k < 3; ++k) {
+ dst[0] = entropy->coeff_probs[i][j][k][4];
+ dst[1] = entropy->coeff_probs[i][j][k][5];
+ dst[2] = entropy->coeff_probs[i][j][k][6];
+ dst[3] = entropy->coeff_probs[i][j][k][7];
+ dst[4] = entropy->coeff_probs[i][j][k][8];
+ dst[5] = entropy->coeff_probs[i][j][k][9];
+ dst[6] = entropy->coeff_probs[i][j][k][10];
+ dst[7] = 0; /*unused */
+ dst += 8;
+ }
+ }
+ }
+}
+
+int hantro_vp8_dec_init(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_aux_buf *aux_buf;
+ unsigned int mb_width, mb_height;
+ size_t segment_map_size;
+ int ret;
+
+ /* segment map table size calculation */
+ mb_width = DIV_ROUND_UP(ctx->dst_fmt.width, 16);
+ mb_height = DIV_ROUND_UP(ctx->dst_fmt.height, 16);
+ segment_map_size = round_up(DIV_ROUND_UP(mb_width * mb_height, 4), 64);
+
+ /*
+ * In context init the dma buffer for segment map must be allocated.
+ * And the data in segment map buffer must be set to all zero.
+ */
+ aux_buf = &ctx->vp8_dec.segment_map;
+ aux_buf->size = segment_map_size;
+ aux_buf->cpu = dma_alloc_coherent(vpu->dev, aux_buf->size,
+ &aux_buf->dma, GFP_KERNEL);
+ if (!aux_buf->cpu)
+ return -ENOMEM;
+
+ /*
+ * Allocate probability table buffer,
+ * total 1208 bytes, 4K page is far enough.
+ */
+ aux_buf = &ctx->vp8_dec.prob_tbl;
+ aux_buf->size = sizeof(struct vp8_prob_tbl_packed);
+ aux_buf->cpu = dma_alloc_coherent(vpu->dev, aux_buf->size,
+ &aux_buf->dma, GFP_KERNEL);
+ if (!aux_buf->cpu) {
+ ret = -ENOMEM;
+ goto err_free_seg_map;
+ }
+
+ return 0;
+
+err_free_seg_map:
+ dma_free_coherent(vpu->dev, ctx->vp8_dec.segment_map.size,
+ ctx->vp8_dec.segment_map.cpu,
+ ctx->vp8_dec.segment_map.dma);
+
+ return ret;
+}
+
+void hantro_vp8_dec_exit(struct hantro_ctx *ctx)
+{
+ struct hantro_vp8_dec_hw_ctx *vp8_dec = &ctx->vp8_dec;
+ struct hantro_dev *vpu = ctx->dev;
+
+ dma_free_coherent(vpu->dev, vp8_dec->segment_map.size,
+ vp8_dec->segment_map.cpu, vp8_dec->segment_map.dma);
+ dma_free_coherent(vpu->dev, vp8_dec->prob_tbl.size,
+ vp8_dec->prob_tbl.cpu, vp8_dec->prob_tbl.dma);
+}
diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c
index bcacc4f51093..6bfcc47d1e58 100644
--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c
+++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c
@@ -62,6 +62,19 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
.codec_mode = HANTRO_MODE_NONE,
},
{
+ .fourcc = V4L2_PIX_FMT_H264_SLICE,
+ .codec_mode = HANTRO_MODE_H264_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 3840,
+ .step_width = H264_MB_DIM,
+ .min_height = 48,
+ .max_height = 2160,
+ .step_height = H264_MB_DIM,
+ },
+ },
+ {
.fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
.codec_mode = HANTRO_MODE_MPEG2_DEC,
.max_depth = 2,
@@ -74,6 +87,19 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
.step_height = MPEG2_MB_DIM,
},
},
+ {
+ .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+ .codec_mode = HANTRO_MODE_VP8_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 3840,
+ .step_width = VP8_MB_DIM,
+ .min_height = 48,
+ .max_height = 2160,
+ .step_height = VP8_MB_DIM,
+ },
+ },
};
static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id)
@@ -149,12 +175,24 @@ static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = {
.init = hantro_jpeg_enc_init,
.exit = hantro_jpeg_enc_exit,
},
+ [HANTRO_MODE_H264_DEC] = {
+ .run = hantro_g1_h264_dec_run,
+ .reset = rk3288_vpu_dec_reset,
+ .init = hantro_h264_dec_init,
+ .exit = hantro_h264_dec_exit,
+ },
[HANTRO_MODE_MPEG2_DEC] = {
.run = hantro_g1_mpeg2_dec_run,
.reset = rk3288_vpu_dec_reset,
.init = hantro_mpeg2_dec_init,
.exit = hantro_mpeg2_dec_exit,
},
+ [HANTRO_MODE_VP8_DEC] = {
+ .run = hantro_g1_vp8_dec_run,
+ .reset = rk3288_vpu_dec_reset,
+ .init = hantro_vp8_dec_init,
+ .exit = hantro_vp8_dec_exit,
+ },
};
/*
@@ -177,7 +215,8 @@ const struct hantro_variant rk3288_vpu_variant = {
.dec_offset = 0x400,
.dec_fmts = rk3288_vpu_dec_fmts,
.num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts),
- .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER,
+ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
+ HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
.codec_ops = rk3288_vpu_codec_ops,
.irqs = rk3288_irqs,
.num_irqs = ARRAY_SIZE(rk3288_irqs),
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c
index 5718f8063542..14d14bc6b12b 100644
--- a/drivers/staging/media/hantro/rk3399_vpu_hw.c
+++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c
@@ -73,6 +73,19 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = {
.step_height = MPEG2_MB_DIM,
},
},
+ {
+ .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+ .codec_mode = HANTRO_MODE_VP8_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 3840,
+ .step_width = VP8_MB_DIM,
+ .min_height = 48,
+ .max_height = 2160,
+ .step_height = VP8_MB_DIM,
+ },
+ },
};
static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id)
@@ -154,6 +167,12 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = {
.init = hantro_mpeg2_dec_init,
.exit = hantro_mpeg2_dec_exit,
},
+ [HANTRO_MODE_VP8_DEC] = {
+ .run = rk3399_vpu_vp8_dec_run,
+ .reset = rk3399_vpu_dec_reset,
+ .init = hantro_vp8_dec_init,
+ .exit = hantro_vp8_dec_exit,
+ },
};
/*
@@ -176,7 +195,8 @@ const struct hantro_variant rk3399_vpu_variant = {
.dec_offset = 0x400,
.dec_fmts = rk3399_vpu_dec_fmts,
.num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
- .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER,
+ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
+ HANTRO_VP8_DECODER,
.codec_ops = rk3399_vpu_codec_ops,
.irqs = rk3399_irqs,
.num_irqs = ARRAY_SIZE(rk3399_irqs),
@@ -184,3 +204,20 @@ const struct hantro_variant rk3399_vpu_variant = {
.clk_names = rk3399_clk_names,
.num_clocks = ARRAY_SIZE(rk3399_clk_names)
};
+
+static const struct hantro_irq rk3328_irqs[] = {
+ { "vdpu", rk3399_vdpu_irq },
+};
+
+const struct hantro_variant rk3328_vpu_variant = {
+ .dec_offset = 0x400,
+ .dec_fmts = rk3399_vpu_dec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
+ .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER,
+ .codec_ops = rk3399_vpu_codec_ops,
+ .irqs = rk3328_irqs,
+ .num_irqs = ARRAY_SIZE(rk3328_irqs),
+ .init = rk3399_vpu_hw_init,
+ .clk_names = rk3399_clk_names,
+ .num_clocks = ARRAY_SIZE(rk3399_clk_names),
+};
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c
index ae66354d2d93..06162f569b5e 100644
--- a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c
+++ b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c
@@ -113,14 +113,12 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
struct hantro_dev *vpu = ctx->dev;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
struct hantro_jpeg_ctx jpeg_ctx;
- struct media_request *src_req;
u32 reg;
- src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ src_buf = hantro_get_src_buf(ctx);
+ dst_buf = hantro_get_dst_buf(ctx);
- src_req = src_buf->vb2_buf.req_obj.req;
- v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler);
+ hantro_prepare_run(ctx);
memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
@@ -157,9 +155,7 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
| VEPU_REG_ENCODE_FORMAT_JPEG
| VEPU_REG_ENCODE_ENABLE;
- v4l2_ctrl_request_complete(src_req, &ctx->ctrl_handler);
-
/* Kick the watchdog and start encoding */
- schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+ hantro_finish_run(ctx);
vepu_write(vpu, reg, VEPU_REG_ENCODE_START);
}
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c
index 8685bddfbcab..e7ba5c0441cc 100644
--- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c
+++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c
@@ -169,12 +169,10 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
const struct v4l2_mpeg2_picture *picture;
u32 reg;
- src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ src_buf = hantro_get_src_buf(ctx);
+ dst_buf = hantro_get_dst_buf(ctx);
- /* Apply request controls if any */
- v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
- &ctx->ctrl_handler);
+ hantro_prepare_run(ctx);
slice_params = hantro_get_ctrl(ctx,
V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
@@ -254,12 +252,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
&dst_buf->vb2_buf,
sequence, picture, slice_params);
- /* Controls no longer in-use, we can complete them */
- v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
- &ctx->ctrl_handler);
-
/* Kick the watchdog and start decoding */
- schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+ hantro_finish_run(ctx);
reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1);
vdpu_write(vpu, reg, VDPU_SWREG(57));
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c
new file mode 100644
index 000000000000..f17e32620b08
--- /dev/null
+++ b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c
@@ -0,0 +1,595 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VPU codec vp8 decode driver
+ *
+ * Copyright (C) 2014 Rockchip Electronics Co., Ltd.
+ * ZhiChao Yu <zhichao.yu@rock-chips.com>
+ *
+ * Copyright (C) 2014 Google LLC.
+ * Tomasz Figa <tfiga@chromium.org>
+ *
+ * Copyright (C) 2015 Rockchip Electronics Co., Ltd.
+ * Alpha Lin <alpha.lin@rock-chips.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include <media/vp8-ctrls.h>
+
+#include "hantro_hw.h"
+#include "hantro.h"
+#include "hantro_g1_regs.h"
+
+#define VDPU_REG_DEC_CTRL0 0x0c8
+#define VDPU_REG_STREAM_LEN 0x0cc
+#define VDPU_REG_DEC_FORMAT 0x0d4
+#define VDPU_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 0)
+#define VDPU_REG_DATA_ENDIAN 0x0d8
+#define VDPU_REG_CONFIG_DEC_STRENDIAN_E BIT(5)
+#define VDPU_REG_CONFIG_DEC_STRSWAP32_E BIT(4)
+#define VDPU_REG_CONFIG_DEC_OUTSWAP32_E BIT(3)
+#define VDPU_REG_CONFIG_DEC_INSWAP32_E BIT(2)
+#define VDPU_REG_CONFIG_DEC_OUT_ENDIAN BIT(1)
+#define VDPU_REG_CONFIG_DEC_IN_ENDIAN BIT(0)
+#define VDPU_REG_AXI_CTRL 0x0e0
+#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 16)
+#define VDPU_REG_EN_FLAGS 0x0e4
+#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(14)
+#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(5)
+#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(4)
+#define VDPU_REG_PRED_FLT 0x0ec
+#define VDPU_REG_ADDR_QTABLE 0x0f4
+#define VDPU_REG_ADDR_DST 0x0fc
+#define VDPU_REG_ADDR_STR 0x100
+#define VDPU_REG_VP8_PIC_MB_SIZE 0x1e0
+#define VDPU_REG_VP8_DCT_START_BIT 0x1e4
+#define VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13)
+#define VDPU_REG_DEC_CTRL4_BILIN_MC_E BIT(12)
+#define VDPU_REG_VP8_CTRL0 0x1e8
+#define VDPU_REG_VP8_DATA_VAL 0x1f0
+#define VDPU_REG_PRED_FLT7 0x1f4
+#define VDPU_REG_PRED_FLT8 0x1f8
+#define VDPU_REG_PRED_FLT9 0x1fc
+#define VDPU_REG_PRED_FLT10 0x200
+#define VDPU_REG_FILTER_LEVEL 0x204
+#define VDPU_REG_VP8_QUANTER0 0x208
+#define VDPU_REG_VP8_ADDR_REF0 0x20c
+#define VDPU_REG_FILTER_MB_ADJ 0x210
+#define VDPU_REG_REF_PIC_FILT_TYPE_E BIT(31)
+#define VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28)
+#define VDPU_REG_FILTER_REF_ADJ 0x214
+#define VDPU_REG_VP8_ADDR_REF2_5(i) (0x218 + ((i) * 0x4))
+#define VDPU_REG_VP8_GREF_SIGN_BIAS BIT(0)
+#define VDPU_REG_VP8_AREF_SIGN_BIAS BIT(0)
+#define VDPU_REG_VP8_DCT_BASE(i) \
+ (0x230 + ((((i) < 5) ? (i) : ((i) + 1)) * 0x4))
+#define VDPU_REG_VP8_ADDR_CTRL_PART 0x244
+#define VDPU_REG_VP8_SEGMENT_VAL 0x254
+#define VDPU_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0)
+#define VDPU_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1)
+#define VDPU_REG_FWD_PIC1_SEGMENT_E BIT(0)
+#define VDPU_REG_VP8_DCT_START_BIT2 0x258
+#define VDPU_REG_VP8_QUANTER1 0x25c
+#define VDPU_REG_VP8_QUANTER2 0x260
+#define VDPU_REG_PRED_FLT1 0x264
+#define VDPU_REG_PRED_FLT2 0x268
+#define VDPU_REG_PRED_FLT3 0x26c
+#define VDPU_REG_PRED_FLT4 0x270
+#define VDPU_REG_PRED_FLT5 0x274
+#define VDPU_REG_PRED_FLT6 0x278
+
+static const struct hantro_reg vp8_dec_dct_base[8] = {
+ { VDPU_REG_ADDR_STR, 0, 0xffffffff },
+ { VDPU_REG_VP8_DCT_BASE(0), 0, 0xffffffff },
+ { VDPU_REG_VP8_DCT_BASE(1), 0, 0xffffffff },
+ { VDPU_REG_VP8_DCT_BASE(2), 0, 0xffffffff },
+ { VDPU_REG_VP8_DCT_BASE(3), 0, 0xffffffff },
+ { VDPU_REG_VP8_DCT_BASE(4), 0, 0xffffffff },
+ { VDPU_REG_VP8_DCT_BASE(5), 0, 0xffffffff },
+ { VDPU_REG_VP8_DCT_BASE(6), 0, 0xffffffff },
+};
+
+static const struct hantro_reg vp8_dec_lf_level[4] = {
+ { VDPU_REG_FILTER_LEVEL, 18, 0x3f },
+ { VDPU_REG_FILTER_LEVEL, 12, 0x3f },
+ { VDPU_REG_FILTER_LEVEL, 6, 0x3f },
+ { VDPU_REG_FILTER_LEVEL, 0, 0x3f },
+};
+
+static const struct hantro_reg vp8_dec_mb_adj[4] = {
+ { VDPU_REG_FILTER_MB_ADJ, 21, 0x7f },
+ { VDPU_REG_FILTER_MB_ADJ, 14, 0x7f },
+ { VDPU_REG_FILTER_MB_ADJ, 7, 0x7f },
+ { VDPU_REG_FILTER_MB_ADJ, 0, 0x7f },
+};
+
+static const struct hantro_reg vp8_dec_ref_adj[4] = {
+ { VDPU_REG_FILTER_REF_ADJ, 21, 0x7f },
+ { VDPU_REG_FILTER_REF_ADJ, 14, 0x7f },
+ { VDPU_REG_FILTER_REF_ADJ, 7, 0x7f },
+ { VDPU_REG_FILTER_REF_ADJ, 0, 0x7f },
+};
+
+static const struct hantro_reg vp8_dec_quant[4] = {
+ { VDPU_REG_VP8_QUANTER0, 11, 0x7ff },
+ { VDPU_REG_VP8_QUANTER0, 0, 0x7ff },
+ { VDPU_REG_VP8_QUANTER1, 11, 0x7ff },
+ { VDPU_REG_VP8_QUANTER1, 0, 0x7ff },
+};
+
+static const struct hantro_reg vp8_dec_quant_delta[5] = {
+ { VDPU_REG_VP8_QUANTER0, 27, 0x1f },
+ { VDPU_REG_VP8_QUANTER0, 22, 0x1f },
+ { VDPU_REG_VP8_QUANTER1, 27, 0x1f },
+ { VDPU_REG_VP8_QUANTER1, 22, 0x1f },
+ { VDPU_REG_VP8_QUANTER2, 27, 0x1f },
+};
+
+static const struct hantro_reg vp8_dec_dct_start_bits[8] = {
+ { VDPU_REG_VP8_CTRL0, 26, 0x3f },
+ { VDPU_REG_VP8_DCT_START_BIT, 26, 0x3f },
+ { VDPU_REG_VP8_DCT_START_BIT, 20, 0x3f },
+ { VDPU_REG_VP8_DCT_START_BIT2, 24, 0x3f },
+ { VDPU_REG_VP8_DCT_START_BIT2, 18, 0x3f },
+ { VDPU_REG_VP8_DCT_START_BIT2, 12, 0x3f },
+ { VDPU_REG_VP8_DCT_START_BIT2, 6, 0x3f },
+ { VDPU_REG_VP8_DCT_START_BIT2, 0, 0x3f },
+};
+
+static const struct hantro_reg vp8_dec_pred_bc_tap[8][6] = {
+ {
+ { 0, 0, 0},
+ { VDPU_REG_PRED_FLT, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT1, 22, 0x3ff },
+ { 0, 0, 0},
+ }, {
+ { 0, 0, 0},
+ { VDPU_REG_PRED_FLT1, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT1, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT2, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT2, 12, 0x3ff },
+ { 0, 0, 0},
+ }, {
+ { VDPU_REG_PRED_FLT10, 10, 0x3 },
+ { VDPU_REG_PRED_FLT2, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT3, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT3, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT3, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT10, 8, 0x3},
+ }, {
+ { 0, 0, 0},
+ { VDPU_REG_PRED_FLT4, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT4, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT4, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT5, 22, 0x3ff },
+ { 0, 0, 0},
+ }, {
+ { VDPU_REG_PRED_FLT10, 6, 0x3 },
+ { VDPU_REG_PRED_FLT5, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT5, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT6, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT6, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT10, 4, 0x3 },
+ }, {
+ { 0, 0, 0},
+ { VDPU_REG_PRED_FLT6, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT7, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT7, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT7, 2, 0x3ff },
+ { 0, 0, 0},
+ }, {
+ { VDPU_REG_PRED_FLT10, 2, 0x3 },
+ { VDPU_REG_PRED_FLT8, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT8, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT8, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT9, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT10, 0, 0x3 },
+ }, {
+ { 0, 0, 0},
+ { VDPU_REG_PRED_FLT9, 12, 0x3ff },
+ { VDPU_REG_PRED_FLT9, 2, 0x3ff },
+ { VDPU_REG_PRED_FLT10, 22, 0x3ff },
+ { VDPU_REG_PRED_FLT10, 12, 0x3ff },
+ { 0, 0, 0},
+ },
+};
+
+static const struct hantro_reg vp8_dec_mb_start_bit = {
+ .base = VDPU_REG_VP8_CTRL0,
+ .shift = 18,
+ .mask = 0x3f
+};
+
+static const struct hantro_reg vp8_dec_mb_aligned_data_len = {
+ .base = VDPU_REG_VP8_DATA_VAL,
+ .shift = 0,
+ .mask = 0x3fffff
+};
+
+static const struct hantro_reg vp8_dec_num_dct_partitions = {
+ .base = VDPU_REG_VP8_DATA_VAL,
+ .shift = 24,
+ .mask = 0xf
+};
+
+static const struct hantro_reg vp8_dec_stream_len = {
+ .base = VDPU_REG_STREAM_LEN,
+ .shift = 0,
+ .mask = 0xffffff
+};
+
+static const struct hantro_reg vp8_dec_mb_width = {
+ .base = VDPU_REG_VP8_PIC_MB_SIZE,
+ .shift = 23,
+ .mask = 0x1ff
+};
+
+static const struct hantro_reg vp8_dec_mb_height = {
+ .base = VDPU_REG_VP8_PIC_MB_SIZE,
+ .shift = 11,
+ .mask = 0xff
+};
+
+static const struct hantro_reg vp8_dec_mb_width_ext = {
+ .base = VDPU_REG_VP8_PIC_MB_SIZE,
+ .shift = 3,
+ .mask = 0x7
+};
+
+static const struct hantro_reg vp8_dec_mb_height_ext = {
+ .base = VDPU_REG_VP8_PIC_MB_SIZE,
+ .shift = 0,
+ .mask = 0x7
+};
+
+static const struct hantro_reg vp8_dec_bool_range = {
+ .base = VDPU_REG_VP8_CTRL0,
+ .shift = 0,
+ .mask = 0xff
+};
+
+static const struct hantro_reg vp8_dec_bool_value = {
+ .base = VDPU_REG_VP8_CTRL0,
+ .shift = 8,
+ .mask = 0xff
+};
+
+static const struct hantro_reg vp8_dec_filter_disable = {
+ .base = VDPU_REG_DEC_CTRL0,
+ .shift = 8,
+ .mask = 1
+};
+
+static const struct hantro_reg vp8_dec_skip_mode = {
+ .base = VDPU_REG_DEC_CTRL0,
+ .shift = 9,
+ .mask = 1
+};
+
+static const struct hantro_reg vp8_dec_start_dec = {
+ .base = VDPU_REG_EN_FLAGS,
+ .shift = 0,
+ .mask = 1
+};
+
+static void cfg_lf(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ const struct v4l2_vp8_segment_header *seg = &hdr->segment_header;
+ const struct v4l2_vp8_loopfilter_header *lf = &hdr->lf_header;
+ struct hantro_dev *vpu = ctx->dev;
+ unsigned int i;
+ u32 reg;
+
+ if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) {
+ hantro_reg_write(vpu, &vp8_dec_lf_level[0], lf->level);
+ } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) {
+ for (i = 0; i < 4; i++) {
+ u32 lf_level = clamp(lf->level + seg->lf_update[i],
+ 0, 63);
+
+ hantro_reg_write(vpu, &vp8_dec_lf_level[i], lf_level);
+ }
+ } else {
+ for (i = 0; i < 4; i++)
+ hantro_reg_write(vpu, &vp8_dec_lf_level[i],
+ seg->lf_update[i]);
+ }
+
+ reg = VDPU_REG_REF_PIC_FILT_SHARPNESS(lf->sharpness_level);
+ if (lf->flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE)
+ reg |= VDPU_REG_REF_PIC_FILT_TYPE_E;
+ vdpu_write_relaxed(vpu, reg, VDPU_REG_FILTER_MB_ADJ);
+
+ if (lf->flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE) {
+ for (i = 0; i < 4; i++) {
+ hantro_reg_write(vpu, &vp8_dec_mb_adj[i],
+ lf->mb_mode_delta[i]);
+ hantro_reg_write(vpu, &vp8_dec_ref_adj[i],
+ lf->ref_frm_delta[i]);
+ }
+ }
+}
+
+static void cfg_qp(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ const struct v4l2_vp8_quantization_header *q = &hdr->quant_header;
+ const struct v4l2_vp8_segment_header *seg = &hdr->segment_header;
+ struct hantro_dev *vpu = ctx->dev;
+ unsigned int i;
+
+ if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) {
+ hantro_reg_write(vpu, &vp8_dec_quant[0], q->y_ac_qi);
+ } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) {
+ for (i = 0; i < 4; i++) {
+ u32 quant = clamp(q->y_ac_qi + seg->quant_update[i],
+ 0, 127);
+
+ hantro_reg_write(vpu, &vp8_dec_quant[i], quant);
+ }
+ } else {
+ for (i = 0; i < 4; i++)
+ hantro_reg_write(vpu, &vp8_dec_quant[i],
+ seg->quant_update[i]);
+ }
+
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[0], q->y_dc_delta);
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[1], q->y2_dc_delta);
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[2], q->y2_ac_delta);
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[3], q->uv_dc_delta);
+ hantro_reg_write(vpu, &vp8_dec_quant_delta[4], q->uv_ac_delta);
+}
+
+static void cfg_parts(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *vb2_src;
+ u32 first_part_offset = VP8_FRAME_IS_KEY_FRAME(hdr) ? 10 : 3;
+ u32 mb_size, mb_offset_bytes, mb_offset_bits, mb_start_bits;
+ u32 dct_size_part_size, dct_part_offset;
+ dma_addr_t src_dma;
+ u32 dct_part_total_len = 0;
+ u32 count = 0;
+ unsigned int i;
+
+ vb2_src = hantro_get_src_buf(ctx);
+ src_dma = vb2_dma_contig_plane_dma_addr(&vb2_src->vb2_buf, 0);
+
+ /*
+ * Calculate control partition mb data info
+ * @first_part_header_bits: bits offset of mb data from first
+ * part start pos
+ * @mb_offset_bits: bits offset of mb data from src_dma
+ * base addr
+ * @mb_offset_byte: bytes offset of mb data from src_dma
+ * base addr
+ * @mb_start_bits: bits offset of mb data from mb data
+ * 64bits alignment addr
+ */
+ mb_offset_bits = first_part_offset * 8 +
+ hdr->first_part_header_bits + 8;
+ mb_offset_bytes = mb_offset_bits / 8;
+ mb_start_bits = mb_offset_bits -
+ (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) * 8;
+ mb_size = hdr->first_part_size -
+ (mb_offset_bytes - first_part_offset) +
+ (mb_offset_bytes & DEC_8190_ALIGN_MASK);
+
+ /* Macroblock data aligned base addr */
+ vdpu_write_relaxed(vpu, (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) +
+ src_dma, VDPU_REG_VP8_ADDR_CTRL_PART);
+ hantro_reg_write(vpu, &vp8_dec_mb_start_bit, mb_start_bits);
+ hantro_reg_write(vpu, &vp8_dec_mb_aligned_data_len, mb_size);
+
+ /*
+ * Calculate DCT partition info
+ * @dct_size_part_size: Containing sizes of DCT part, every DCT part
+ * has 3 bytes to store its size, except the last
+ * DCT part
+ * @dct_part_offset: bytes offset of DCT parts from src_dma base addr
+ * @dct_part_total_len: total size of all DCT parts
+ */
+ dct_size_part_size = (hdr->num_dct_parts - 1) * 3;
+ dct_part_offset = first_part_offset + hdr->first_part_size;
+ for (i = 0; i < hdr->num_dct_parts; i++)
+ dct_part_total_len += hdr->dct_part_sizes[i];
+ dct_part_total_len += dct_size_part_size;
+ dct_part_total_len += (dct_part_offset & DEC_8190_ALIGN_MASK);
+
+ /* Number of DCT partitions */
+ hantro_reg_write(vpu, &vp8_dec_num_dct_partitions,
+ hdr->num_dct_parts - 1);
+
+ /* DCT partition length */
+ hantro_reg_write(vpu, &vp8_dec_stream_len, dct_part_total_len);
+
+ /* DCT partitions base address */
+ for (i = 0; i < hdr->num_dct_parts; i++) {
+ u32 byte_offset = dct_part_offset + dct_size_part_size + count;
+ u32 base_addr = byte_offset + src_dma;
+
+ hantro_reg_write(vpu, &vp8_dec_dct_base[i],
+ base_addr & (~DEC_8190_ALIGN_MASK));
+
+ hantro_reg_write(vpu, &vp8_dec_dct_start_bits[i],
+ (byte_offset & DEC_8190_ALIGN_MASK) * 8);
+
+ count += hdr->dct_part_sizes[i];
+ }
+}
+
+/*
+ * prediction filter taps
+ * normal 6-tap filters
+ */
+static void cfg_tap(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ int i, j;
+
+ if ((hdr->version & 0x03) != 0)
+ return; /* Tap filter not used. */
+
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 6; j++) {
+ if (vp8_dec_pred_bc_tap[i][j].base != 0)
+ hantro_reg_write(vpu,
+ &vp8_dec_pred_bc_tap[i][j],
+ hantro_vp8_dec_mc_filter[i][j]);
+ }
+ }
+}
+
+static void cfg_ref(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *vb2_dst;
+ struct vb2_queue *cap_q;
+ dma_addr_t ref;
+
+ cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ vb2_dst = hantro_get_dst_buf(ctx);
+
+ ref = hantro_get_ref(cap_q, hdr->last_frame_ts);
+ if (!ref)
+ ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0);
+ vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF0);
+
+ ref = hantro_get_ref(cap_q, hdr->golden_frame_ts);
+ WARN_ON(!ref && hdr->golden_frame_ts);
+ if (!ref)
+ ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0);
+ if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN)
+ ref |= VDPU_REG_VP8_GREF_SIGN_BIAS;
+ vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(2));
+
+ ref = hantro_get_ref(cap_q, hdr->alt_frame_ts);
+ WARN_ON(!ref && hdr->alt_frame_ts);
+ if (!ref)
+ ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0);
+ if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT)
+ ref |= VDPU_REG_VP8_AREF_SIGN_BIAS;
+ vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(3));
+}
+
+static void cfg_buffers(struct hantro_ctx *ctx,
+ const struct v4l2_ctrl_vp8_frame_header *hdr)
+{
+ const struct v4l2_vp8_segment_header *seg = &hdr->segment_header;
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *vb2_dst;
+ dma_addr_t dst_dma;
+ u32 reg;
+
+ vb2_dst = hantro_get_dst_buf(ctx);
+
+ /* Set probability table buffer address */
+ vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma,
+ VDPU_REG_ADDR_QTABLE);
+
+ /* Set segment map address */
+ reg = VDPU_REG_FWD_PIC1_SEGMENT_BASE(ctx->vp8_dec.segment_map.dma);
+ if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED) {
+ reg |= VDPU_REG_FWD_PIC1_SEGMENT_E;
+ if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP)
+ reg |= VDPU_REG_FWD_PIC1_SEGMENT_UPD_E;
+ }
+ vdpu_write_relaxed(vpu, reg, VDPU_REG_VP8_SEGMENT_VAL);
+
+ /* set output frame buffer address */
+ dst_dma = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0);
+ vdpu_write_relaxed(vpu, dst_dma, VDPU_REG_ADDR_DST);
+}
+
+void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx)
+{
+ const struct v4l2_ctrl_vp8_frame_header *hdr;
+ struct hantro_dev *vpu = ctx->dev;
+ size_t height = ctx->dst_fmt.height;
+ size_t width = ctx->dst_fmt.width;
+ u32 mb_width, mb_height;
+ u32 reg;
+
+ hantro_prepare_run(ctx);
+
+ hdr = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER);
+ if (WARN_ON(!hdr))
+ return;
+
+ /* Reset segment_map buffer in keyframe */
+ if (VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu)
+ memset(ctx->vp8_dec.segment_map.cpu, 0,
+ ctx->vp8_dec.segment_map.size);
+
+ hantro_vp8_prob_update(ctx, hdr);
+
+ /*
+ * Extensive testing shows that the hardware does not properly
+ * clear the internal state from previous a decoding run. This
+ * causes corruption in decoded frames for multi-instance use cases.
+ * A soft reset before programming the registers has been found
+ * to resolve those problems.
+ */
+ ctx->codec_ops->reset(ctx);
+
+ reg = VDPU_REG_CONFIG_DEC_TIMEOUT_E
+ | VDPU_REG_CONFIG_DEC_CLK_GATE_E;
+ if (!VP8_FRAME_IS_KEY_FRAME(hdr))
+ reg |= VDPU_REG_DEC_CTRL0_PIC_INTER_E;
+ vdpu_write_relaxed(vpu, reg, VDPU_REG_EN_FLAGS);
+
+ reg = VDPU_REG_CONFIG_DEC_STRENDIAN_E
+ | VDPU_REG_CONFIG_DEC_INSWAP32_E
+ | VDPU_REG_CONFIG_DEC_STRSWAP32_E
+ | VDPU_REG_CONFIG_DEC_OUTSWAP32_E
+ | VDPU_REG_CONFIG_DEC_IN_ENDIAN
+ | VDPU_REG_CONFIG_DEC_OUT_ENDIAN;
+ vdpu_write_relaxed(vpu, reg, VDPU_REG_DATA_ENDIAN);
+
+ reg = VDPU_REG_CONFIG_DEC_MAX_BURST(16);
+ vdpu_write_relaxed(vpu, reg, VDPU_REG_AXI_CTRL);
+
+ reg = VDPU_REG_DEC_CTRL0_DEC_MODE(10);
+ vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_FORMAT);
+
+ if (!(hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF))
+ hantro_reg_write(vpu, &vp8_dec_skip_mode, 1);
+ if (hdr->lf_header.level == 0)
+ hantro_reg_write(vpu, &vp8_dec_filter_disable, 1);
+
+ /* Frame dimensions */
+ mb_width = VP8_MB_WIDTH(width);
+ mb_height = VP8_MB_HEIGHT(height);
+
+ hantro_reg_write(vpu, &vp8_dec_mb_width, mb_width);
+ hantro_reg_write(vpu, &vp8_dec_mb_height, mb_height);
+ hantro_reg_write(vpu, &vp8_dec_mb_width_ext, mb_width >> 9);
+ hantro_reg_write(vpu, &vp8_dec_mb_height_ext, mb_height >> 8);
+
+ /* Boolean decoder */
+ hantro_reg_write(vpu, &vp8_dec_bool_range, hdr->coder_state.range);
+ hantro_reg_write(vpu, &vp8_dec_bool_value, hdr->coder_state.value);
+
+ reg = vdpu_read(vpu, VDPU_REG_VP8_DCT_START_BIT);
+ if (hdr->version != 3)
+ reg |= VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT;
+ if (hdr->version & 0x3)
+ reg |= VDPU_REG_DEC_CTRL4_BILIN_MC_E;
+ vdpu_write_relaxed(vpu, reg, VDPU_REG_VP8_DCT_START_BIT);
+
+ cfg_lf(ctx, hdr);
+ cfg_qp(ctx, hdr);
+ cfg_parts(ctx, hdr);
+ cfg_tap(ctx, hdr);
+ cfg_ref(ctx, hdr);
+ cfg_buffers(ctx, hdr);
+
+ hantro_finish_run(ctx);
+
+ hantro_reg_write(vpu, &vp8_dec_start_dec, 1);
+}
diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig
index 4c726345dc25..8f1ae50a4abd 100644
--- a/drivers/staging/media/imx/Kconfig
+++ b/drivers/staging/media/imx/Kconfig
@@ -7,6 +7,7 @@ config VIDEO_IMX_MEDIA
depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
+ select V4L2_MEM2MEM_DEV
help
Say yes here to enable support for video4linux media controller
driver for the i.MX5/6 SOC.
@@ -22,11 +23,11 @@ config VIDEO_IMX_CSI
A video4linux camera sensor interface driver for i.MX5/6.
config VIDEO_IMX7_CSI
- tristate "i.MX7 Camera Sensor Interface driver"
+ tristate "i.MX6UL/L / i.MX7 Camera Sensor Interface driver"
depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C
default y
help
Enable support for video4linux camera sensor interface driver for
- i.MX7.
+ i.MX6UL/L or i.MX7.
endmenu
endif
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index aa6c4b4ad37e..9bd9e873ba7c 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
imx6-media-objs := imx-media-dev.o imx-media-internal-sd.o \
- imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o
+ imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o \
+ imx-media-csc-scaler.o
imx-media-common-objs := imx-media-capture.o imx-media-dev-common.o \
imx-media-of.o imx-media-utils.o
diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c
new file mode 100644
index 000000000000..2b635ebf62d6
--- /dev/null
+++ b/drivers/staging/media/imx/imx-media-csc-scaler.c
@@ -0,0 +1,925 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * i.MX IPUv3 IC PP mem2mem CSC/Scaler driver
+ *
+ * Copyright (C) 2011 Pengutronix, Sascha Hauer
+ * Copyright (C) 2018 Pengutronix, Philipp Zabel
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <video/imx-ipu-v3.h>
+#include <video/imx-ipu-image-convert.h>
+
+#include <media/media-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "imx-media.h"
+
+#define fh_to_ctx(__fh) container_of(__fh, struct ipu_csc_scaler_ctx, fh)
+
+enum {
+ V4L2_M2M_SRC = 0,
+ V4L2_M2M_DST = 1,
+};
+
+struct ipu_csc_scaler_priv {
+ struct imx_media_video_dev vdev;
+
+ struct v4l2_m2m_dev *m2m_dev;
+ struct device *dev;
+
+ struct imx_media_dev *md;
+
+ struct mutex mutex; /* mem2mem device mutex */
+};
+
+#define vdev_to_priv(v) container_of(v, struct ipu_csc_scaler_priv, vdev)
+
+/* Per-queue, driver-specific private data */
+struct ipu_csc_scaler_q_data {
+ struct v4l2_pix_format cur_fmt;
+ struct v4l2_rect rect;
+};
+
+struct ipu_csc_scaler_ctx {
+ struct ipu_csc_scaler_priv *priv;
+
+ struct v4l2_fh fh;
+ struct ipu_csc_scaler_q_data q_data[2];
+ struct ipu_image_convert_ctx *icc;
+
+ struct v4l2_ctrl_handler ctrl_hdlr;
+ int rotate;
+ bool hflip;
+ bool vflip;
+ enum ipu_rotate_mode rot_mode;
+ unsigned int sequence;
+};
+
+static struct ipu_csc_scaler_q_data *get_q_data(struct ipu_csc_scaler_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ if (V4L2_TYPE_IS_OUTPUT(type))
+ return &ctx->q_data[V4L2_M2M_SRC];
+ else
+ return &ctx->q_data[V4L2_M2M_DST];
+}
+
+/*
+ * mem2mem callbacks
+ */
+
+static void job_abort(void *_ctx)
+{
+ struct ipu_csc_scaler_ctx *ctx = _ctx;
+
+ if (ctx->icc)
+ ipu_image_convert_abort(ctx->icc);
+}
+
+static void ipu_ic_pp_complete(struct ipu_image_convert_run *run, void *_ctx)
+{
+ struct ipu_csc_scaler_ctx *ctx = _ctx;
+ struct ipu_csc_scaler_priv *priv = ctx->priv;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+
+ src_buf->sequence = ctx->sequence++;
+ dst_buf->sequence = src_buf->sequence;
+
+ v4l2_m2m_buf_done(src_buf, run->status ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_buf, run->status ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_DONE);
+
+ v4l2_m2m_job_finish(priv->m2m_dev, ctx->fh.m2m_ctx);
+ kfree(run);
+}
+
+static void device_run(void *_ctx)
+{
+ struct ipu_csc_scaler_ctx *ctx = _ctx;
+ struct ipu_csc_scaler_priv *priv = ctx->priv;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ struct ipu_image_convert_run *run;
+ int ret;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ run = kzalloc(sizeof(*run), GFP_KERNEL);
+ if (!run)
+ goto err;
+
+ run->ctx = ctx->icc;
+ run->in_phys = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ run->out_phys = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+
+ ret = ipu_image_convert_queue(run);
+ if (ret < 0) {
+ v4l2_err(ctx->priv->vdev.vfd->v4l2_dev,
+ "%s: failed to queue: %d\n", __func__, ret);
+ goto err;
+ }
+
+ return;
+
+err:
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_job_finish(priv->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+/*
+ * Video ioctls
+ */
+static int ipu_csc_scaler_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, "imx-media-csc-scaler", sizeof(cap->driver));
+ strscpy(cap->card, "imx-media-csc-scaler", sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:imx-media-csc-scaler",
+ sizeof(cap->bus_info));
+
+ return 0;
+}
+
+static int ipu_csc_scaler_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ u32 fourcc;
+ int ret;
+
+ ret = imx_media_enum_format(&fourcc, f->index, CS_SEL_ANY);
+ if (ret)
+ return ret;
+
+ f->pixelformat = fourcc;
+
+ return 0;
+}
+
+static int ipu_csc_scaler_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv);
+ struct ipu_csc_scaler_q_data *q_data;
+
+ q_data = get_q_data(ctx, f->type);
+
+ f->fmt.pix = q_data->cur_fmt;
+
+ return 0;
+}
+
+static int ipu_csc_scaler_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv);
+ struct ipu_csc_scaler_q_data *q_data = get_q_data(ctx, f->type);
+ struct ipu_image test_in, test_out;
+ enum v4l2_field field;
+
+ field = f->fmt.pix.field;
+ if (field == V4L2_FIELD_ANY)
+ field = V4L2_FIELD_NONE;
+ else if (field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ struct ipu_csc_scaler_q_data *q_data_in =
+ get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ test_out.pix = f->fmt.pix;
+ test_in.pix = q_data_in->cur_fmt;
+ } else {
+ struct ipu_csc_scaler_q_data *q_data_out =
+ get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ test_in.pix = f->fmt.pix;
+ test_out.pix = q_data_out->cur_fmt;
+ }
+
+ ipu_image_convert_adjust(&test_in, &test_out, ctx->rot_mode);
+
+ f->fmt.pix = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+ test_out.pix : test_in.pix;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ f->fmt.pix.colorspace = q_data->cur_fmt.colorspace;
+ f->fmt.pix.ycbcr_enc = q_data->cur_fmt.ycbcr_enc;
+ f->fmt.pix.xfer_func = q_data->cur_fmt.xfer_func;
+ f->fmt.pix.quantization = q_data->cur_fmt.quantization;
+ } else if (f->fmt.pix.colorspace == V4L2_COLORSPACE_DEFAULT) {
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+ f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
+ }
+
+ return 0;
+}
+
+static int ipu_csc_scaler_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct ipu_csc_scaler_q_data *q_data;
+ struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv);
+ struct vb2_queue *vq;
+ int ret;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (vb2_is_busy(vq)) {
+ v4l2_err(ctx->priv->vdev.vfd->v4l2_dev, "%s: queue busy\n",
+ __func__);
+ return -EBUSY;
+ }
+
+ q_data = get_q_data(ctx, f->type);
+
+ ret = ipu_csc_scaler_try_fmt(file, priv, f);
+ if (ret < 0)
+ return ret;
+
+ q_data->cur_fmt.width = f->fmt.pix.width;
+ q_data->cur_fmt.height = f->fmt.pix.height;
+ q_data->cur_fmt.pixelformat = f->fmt.pix.pixelformat;
+ q_data->cur_fmt.field = f->fmt.pix.field;
+ q_data->cur_fmt.bytesperline = f->fmt.pix.bytesperline;
+ q_data->cur_fmt.sizeimage = f->fmt.pix.sizeimage;
+
+ /* Reset cropping/composing rectangle */
+ q_data->rect.left = 0;
+ q_data->rect.top = 0;
+ q_data->rect.width = q_data->cur_fmt.width;
+ q_data->rect.height = q_data->cur_fmt.height;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ /* Set colorimetry on the output queue */
+ q_data->cur_fmt.colorspace = f->fmt.pix.colorspace;
+ q_data->cur_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ q_data->cur_fmt.xfer_func = f->fmt.pix.xfer_func;
+ q_data->cur_fmt.quantization = f->fmt.pix.quantization;
+ /* Propagate colorimetry to the capture queue */
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ q_data->cur_fmt.colorspace = f->fmt.pix.colorspace;
+ q_data->cur_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ q_data->cur_fmt.xfer_func = f->fmt.pix.xfer_func;
+ q_data->cur_fmt.quantization = f->fmt.pix.quantization;
+ }
+
+ /*
+ * TODO: Setting colorimetry on the capture queue is currently not
+ * supported by the V4L2 API
+ */
+
+ return 0;
+}
+
+static int ipu_csc_scaler_g_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
+{
+ struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv);
+ struct ipu_csc_scaler_q_data *q_data;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (s->target == V4L2_SEL_TGT_CROP ||
+ s->target == V4L2_SEL_TGT_COMPOSE) {
+ s->r = q_data->rect;
+ } else {
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = q_data->cur_fmt.width;
+ s->r.height = q_data->cur_fmt.height;
+ }
+
+ return 0;
+}
+
+static int ipu_csc_scaler_s_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
+{
+ struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv);
+ struct ipu_csc_scaler_q_data *q_data;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP:
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ q_data = get_q_data(ctx, s->type);
+
+ /* The input's frame width to the IC must be a multiple of 8 pixels
+ * When performing resizing the frame width must be multiple of burst
+ * size - 8 or 16 pixels as defined by CB#_BURST_16 parameter.
+ */
+ if (s->flags & V4L2_SEL_FLAG_GE)
+ s->r.width = round_up(s->r.width, 8);
+ if (s->flags & V4L2_SEL_FLAG_LE)
+ s->r.width = round_down(s->r.width, 8);
+ s->r.width = clamp_t(unsigned int, s->r.width, 8,
+ round_down(q_data->cur_fmt.width, 8));
+ s->r.height = clamp_t(unsigned int, s->r.height, 1,
+ q_data->cur_fmt.height);
+ s->r.left = clamp_t(unsigned int, s->r.left, 0,
+ q_data->cur_fmt.width - s->r.width);
+ s->r.top = clamp_t(unsigned int, s->r.top, 0,
+ q_data->cur_fmt.height - s->r.height);
+
+ /* V4L2_SEL_FLAG_KEEP_CONFIG is only valid for subdevices */
+ q_data->rect = s->r;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops ipu_csc_scaler_ioctl_ops = {
+ .vidioc_querycap = ipu_csc_scaler_querycap,
+
+ .vidioc_enum_fmt_vid_cap = ipu_csc_scaler_enum_fmt,
+ .vidioc_g_fmt_vid_cap = ipu_csc_scaler_g_fmt,
+ .vidioc_try_fmt_vid_cap = ipu_csc_scaler_try_fmt,
+ .vidioc_s_fmt_vid_cap = ipu_csc_scaler_s_fmt,
+
+ .vidioc_enum_fmt_vid_out = ipu_csc_scaler_enum_fmt,
+ .vidioc_g_fmt_vid_out = ipu_csc_scaler_g_fmt,
+ .vidioc_try_fmt_vid_out = ipu_csc_scaler_try_fmt,
+ .vidioc_s_fmt_vid_out = ipu_csc_scaler_s_fmt,
+
+ .vidioc_g_selection = ipu_csc_scaler_g_selection,
+ .vidioc_s_selection = ipu_csc_scaler_s_selection,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/*
+ * Queue operations
+ */
+
+static int ipu_csc_scaler_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers,
+ unsigned int *nplanes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vq);
+ struct ipu_csc_scaler_q_data *q_data;
+ unsigned int size, count = *nbuffers;
+
+ q_data = get_q_data(ctx, vq->type);
+
+ size = q_data->cur_fmt.sizeimage;
+
+ *nbuffers = count;
+
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *nplanes = 1;
+ sizes[0] = size;
+
+ dev_dbg(ctx->priv->dev, "get %d buffer(s) of size %d each.\n",
+ count, size);
+
+ return 0;
+}
+
+static int ipu_csc_scaler_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vq);
+ struct ipu_csc_scaler_q_data *q_data;
+ unsigned long size;
+
+ dev_dbg(ctx->priv->dev, "type: %d\n", vq->type);
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+ if (vbuf->field == V4L2_FIELD_ANY)
+ vbuf->field = V4L2_FIELD_NONE;
+ if (vbuf->field != V4L2_FIELD_NONE) {
+ dev_dbg(ctx->priv->dev, "%s: field isn't supported\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ q_data = get_q_data(ctx, vq->type);
+ size = q_data->cur_fmt.sizeimage;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ dev_dbg(ctx->priv->dev,
+ "%s: data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, size);
+
+ return 0;
+}
+
+static void ipu_csc_scaler_buf_queue(struct vb2_buffer *vb)
+{
+ struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb));
+}
+
+static void ipu_image_from_q_data(struct ipu_image *im,
+ struct ipu_csc_scaler_q_data *q_data)
+{
+ struct v4l2_pix_format *fmt = &q_data->cur_fmt;
+
+ im->pix = *fmt;
+ if (fmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+ im->pix.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ if (fmt->quantization == V4L2_QUANTIZATION_DEFAULT)
+ im->pix.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ im->rect = q_data->rect;
+}
+
+static int ipu_csc_scaler_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ const enum ipu_ic_task ic_task = IC_TASK_POST_PROCESSOR;
+ struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(q);
+ struct ipu_csc_scaler_priv *priv = ctx->priv;
+ struct ipu_soc *ipu = priv->md->ipu[0];
+ struct ipu_csc_scaler_q_data *q_data;
+ struct vb2_queue *other_q;
+ struct ipu_image in, out;
+
+ other_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+ V4L2_BUF_TYPE_VIDEO_OUTPUT :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (!vb2_is_streaming(other_q))
+ return 0;
+
+ if (ctx->icc) {
+ v4l2_warn(ctx->priv->vdev.vfd->v4l2_dev, "removing old ICC\n");
+ ipu_image_convert_unprepare(ctx->icc);
+ }
+
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ ipu_image_from_q_data(&in, q_data);
+
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ipu_image_from_q_data(&out, q_data);
+
+ ctx->icc = ipu_image_convert_prepare(ipu, ic_task, &in, &out,
+ ctx->rot_mode,
+ ipu_ic_pp_complete, ctx);
+ if (IS_ERR(ctx->icc)) {
+ struct vb2_v4l2_buffer *buf;
+ int ret = PTR_ERR(ctx->icc);
+
+ ctx->icc = NULL;
+ v4l2_err(ctx->priv->vdev.vfd->v4l2_dev, "%s: error %d\n",
+ __func__, ret);
+ while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
+ while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ipu_csc_scaler_stop_streaming(struct vb2_queue *q)
+{
+ struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_v4l2_buffer *buf;
+
+ if (ctx->icc) {
+ ipu_image_convert_unprepare(ctx->icc);
+ ctx->icc = NULL;
+ }
+
+ ctx->sequence = 0;
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+ } else {
+ while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+ }
+}
+
+static const struct vb2_ops ipu_csc_scaler_qops = {
+ .queue_setup = ipu_csc_scaler_queue_setup,
+ .buf_prepare = ipu_csc_scaler_buf_prepare,
+ .buf_queue = ipu_csc_scaler_buf_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = ipu_csc_scaler_start_streaming,
+ .stop_streaming = ipu_csc_scaler_stop_streaming,
+};
+
+static int ipu_csc_scaler_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct ipu_csc_scaler_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &ipu_csc_scaler_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->priv->mutex;
+ src_vq->dev = ctx->priv->dev;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &ipu_csc_scaler_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->priv->mutex;
+ dst_vq->dev = ctx->priv->dev;
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int ipu_csc_scaler_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ipu_csc_scaler_ctx *ctx = container_of(ctrl->handler,
+ struct ipu_csc_scaler_ctx,
+ ctrl_hdlr);
+ enum ipu_rotate_mode rot_mode;
+ int rotate;
+ bool hflip, vflip;
+ int ret = 0;
+
+ rotate = ctx->rotate;
+ hflip = ctx->hflip;
+ vflip = ctx->vflip;
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ hflip = ctrl->val;
+ break;
+ case V4L2_CID_VFLIP:
+ vflip = ctrl->val;
+ break;
+ case V4L2_CID_ROTATE:
+ rotate = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = ipu_degrees_to_rot_mode(&rot_mode, rotate, hflip, vflip);
+ if (ret)
+ return ret;
+
+ if (rot_mode != ctx->rot_mode) {
+ struct v4l2_pix_format *in_fmt, *out_fmt;
+ struct ipu_image test_in, test_out;
+
+ in_fmt = &ctx->q_data[V4L2_M2M_SRC].cur_fmt;
+ out_fmt = &ctx->q_data[V4L2_M2M_DST].cur_fmt;
+
+ test_in.pix = *in_fmt;
+ test_out.pix = *out_fmt;
+
+ if (ipu_rot_mode_is_irt(rot_mode) !=
+ ipu_rot_mode_is_irt(ctx->rot_mode)) {
+ /* Switch width & height to keep aspect ratio intact */
+ test_out.pix.width = out_fmt->height;
+ test_out.pix.height = out_fmt->width;
+ }
+
+ ipu_image_convert_adjust(&test_in, &test_out, ctx->rot_mode);
+
+ /* Check if output format needs to be changed */
+ if (test_in.pix.width != in_fmt->width ||
+ test_in.pix.height != in_fmt->height ||
+ test_in.pix.bytesperline != in_fmt->bytesperline ||
+ test_in.pix.sizeimage != in_fmt->sizeimage) {
+ struct vb2_queue *out_q;
+
+ out_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ if (vb2_is_busy(out_q))
+ return -EBUSY;
+ }
+
+ /* Check if capture format needs to be changed */
+ if (test_out.pix.width != out_fmt->width ||
+ test_out.pix.height != out_fmt->height ||
+ test_out.pix.bytesperline != out_fmt->bytesperline ||
+ test_out.pix.sizeimage != out_fmt->sizeimage) {
+ struct vb2_queue *cap_q;
+
+ cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (vb2_is_busy(cap_q))
+ return -EBUSY;
+ }
+
+ *in_fmt = test_in.pix;
+ *out_fmt = test_out.pix;
+
+ ctx->rot_mode = rot_mode;
+ ctx->rotate = rotate;
+ ctx->hflip = hflip;
+ ctx->vflip = vflip;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops ipu_csc_scaler_ctrl_ops = {
+ .s_ctrl = ipu_csc_scaler_s_ctrl,
+};
+
+static int ipu_csc_scaler_init_controls(struct ipu_csc_scaler_ctx *ctx)
+{
+ struct v4l2_ctrl_handler *hdlr = &ctx->ctrl_hdlr;
+
+ v4l2_ctrl_handler_init(hdlr, 3);
+
+ v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_ROTATE,
+ 0, 270, 90, 0);
+
+ if (hdlr->error) {
+ v4l2_ctrl_handler_free(hdlr);
+ return hdlr->error;
+ }
+
+ v4l2_ctrl_handler_setup(hdlr);
+ return 0;
+}
+
+#define DEFAULT_WIDTH 720
+#define DEFAULT_HEIGHT 576
+static const struct ipu_csc_scaler_q_data ipu_csc_scaler_q_data_default = {
+ .cur_fmt = {
+ .width = DEFAULT_WIDTH,
+ .height = DEFAULT_HEIGHT,
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .field = V4L2_FIELD_NONE,
+ .bytesperline = DEFAULT_WIDTH,
+ .sizeimage = DEFAULT_WIDTH * DEFAULT_HEIGHT * 3 / 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ },
+ .rect = {
+ .width = DEFAULT_WIDTH,
+ .height = DEFAULT_HEIGHT,
+ },
+};
+
+/*
+ * File operations
+ */
+static int ipu_csc_scaler_open(struct file *file)
+{
+ struct ipu_csc_scaler_priv *priv = video_drvdata(file);
+ struct ipu_csc_scaler_ctx *ctx = NULL;
+ int ret;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->rot_mode = IPU_ROTATE_NONE;
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+ ctx->priv = priv;
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(priv->m2m_dev, ctx,
+ &ipu_csc_scaler_queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ goto err_ctx;
+ }
+
+ ret = ipu_csc_scaler_init_controls(ctx);
+ if (ret)
+ goto err_ctrls;
+
+ ctx->fh.ctrl_handler = &ctx->ctrl_hdlr;
+
+ ctx->q_data[V4L2_M2M_SRC] = ipu_csc_scaler_q_data_default;
+ ctx->q_data[V4L2_M2M_DST] = ipu_csc_scaler_q_data_default;
+
+ dev_dbg(priv->dev, "Created instance %p, m2m_ctx: %p\n", ctx,
+ ctx->fh.m2m_ctx);
+
+ return 0;
+
+err_ctrls:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+err_ctx:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ return ret;
+}
+
+static int ipu_csc_scaler_release(struct file *file)
+{
+ struct ipu_csc_scaler_priv *priv = video_drvdata(file);
+ struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(file->private_data);
+
+ dev_dbg(priv->dev, "Releasing instance %p\n", ctx);
+
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations ipu_csc_scaler_fops = {
+ .owner = THIS_MODULE,
+ .open = ipu_csc_scaler_open,
+ .release = ipu_csc_scaler_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+ .device_run = device_run,
+ .job_abort = job_abort,
+};
+
+static void ipu_csc_scaler_video_device_release(struct video_device *vdev)
+{
+ struct ipu_csc_scaler_priv *priv = video_get_drvdata(vdev);
+
+ v4l2_m2m_release(priv->m2m_dev);
+ video_device_release(vdev);
+ kfree(priv);
+}
+
+static const struct video_device ipu_csc_scaler_videodev_template = {
+ .name = "ipu_ic_pp csc/scaler",
+ .fops = &ipu_csc_scaler_fops,
+ .ioctl_ops = &ipu_csc_scaler_ioctl_ops,
+ .minor = -1,
+ .release = ipu_csc_scaler_video_device_release,
+ .vfl_dir = VFL_DIR_M2M,
+ .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+int imx_media_csc_scaler_device_register(struct imx_media_video_dev *vdev)
+{
+ struct ipu_csc_scaler_priv *priv = vdev_to_priv(vdev);
+ struct video_device *vfd = vdev->vfd;
+ int ret;
+
+ vfd->v4l2_dev = &priv->md->v4l2_dev;
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(vfd->v4l2_dev, "Failed to register video device\n");
+ return ret;
+ }
+
+ v4l2_info(vfd->v4l2_dev, "Registered %s as /dev/%s\n", vfd->name,
+ video_device_node_name(vfd));
+
+ return 0;
+}
+
+void imx_media_csc_scaler_device_unregister(struct imx_media_video_dev *vdev)
+{
+ struct ipu_csc_scaler_priv *priv = vdev_to_priv(vdev);
+ struct video_device *vfd = priv->vdev.vfd;
+
+ mutex_lock(&priv->mutex);
+
+ video_unregister_device(vfd);
+
+ mutex_unlock(&priv->mutex);
+}
+
+struct imx_media_video_dev *
+imx_media_csc_scaler_device_init(struct imx_media_dev *md)
+{
+ struct ipu_csc_scaler_priv *priv;
+ struct video_device *vfd;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return ERR_PTR(-ENOMEM);
+
+ priv->md = md;
+ priv->dev = md->md.dev;
+
+ mutex_init(&priv->mutex);
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ ret = -ENOMEM;
+ goto err_vfd;
+ }
+
+ *vfd = ipu_csc_scaler_videodev_template;
+ vfd->lock = &priv->mutex;
+ priv->vdev.vfd = vfd;
+
+ INIT_LIST_HEAD(&priv->vdev.list);
+
+ video_set_drvdata(vfd, priv);
+
+ priv->m2m_dev = v4l2_m2m_init(&m2m_ops);
+ if (IS_ERR(priv->m2m_dev)) {
+ ret = PTR_ERR(priv->m2m_dev);
+ v4l2_err(&md->v4l2_dev, "Failed to init mem2mem device: %d\n",
+ ret);
+ goto err_m2m;
+ }
+
+ return &priv->vdev;
+
+err_m2m:
+ video_set_drvdata(vfd, NULL);
+err_vfd:
+ kfree(priv);
+ return ERR_PTR(ret);
+}
+
+MODULE_DESCRIPTION("i.MX IPUv3 mem2mem scaler/CSC driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index 6ac371f6e971..2c3c2adca683 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -38,9 +38,34 @@ static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
}
/* async subdev complete notifier */
+static int imx6_media_probe_complete(struct v4l2_async_notifier *notifier)
+{
+ struct imx_media_dev *imxmd = notifier2dev(notifier);
+ int ret;
+
+ /* call the imx5/6/7 common probe completion handler */
+ ret = imx_media_probe_complete(notifier);
+ if (ret)
+ return ret;
+
+ mutex_lock(&imxmd->mutex);
+
+ imxmd->m2m_vdev = imx_media_csc_scaler_device_init(imxmd);
+ if (IS_ERR(imxmd->m2m_vdev)) {
+ ret = PTR_ERR(imxmd->m2m_vdev);
+ goto unlock;
+ }
+
+ ret = imx_media_csc_scaler_device_register(imxmd->m2m_vdev);
+unlock:
+ mutex_unlock(&imxmd->mutex);
+ return ret;
+}
+
+/* async subdev complete notifier */
static const struct v4l2_async_notifier_operations imx_media_notifier_ops = {
.bound = imx_media_subdev_bound,
- .complete = imx_media_probe_complete,
+ .complete = imx6_media_probe_complete,
};
static int imx_media_probe(struct platform_device *pdev)
@@ -85,6 +110,7 @@ static int imx_media_remove(struct platform_device *pdev)
v4l2_async_notifier_unregister(&imxmd->notifier);
imx_media_unregister_ipu_internal_subdevs(imxmd);
v4l2_async_notifier_cleanup(&imxmd->notifier);
+ imx_media_csc_scaler_device_unregister(imxmd->m2m_vdev);
media_device_unregister(&imxmd->md);
v4l2_device_unregister(&imxmd->v4l2_dev);
media_device_cleanup(&imxmd->md);
diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c
index cb1e4cdd5079..d4237e1a4241 100644
--- a/drivers/staging/media/imx/imx-media-internal-sd.c
+++ b/drivers/staging/media/imx/imx-media-internal-sd.c
@@ -210,6 +210,10 @@ int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd,
mutex_lock(&imxmd->mutex);
+ /* record this IPU */
+ if (!imxmd->ipu[ipu_id])
+ imxmd->ipu[ipu_id] = ipu;
+
/* register the synchronous subdevs */
for (i = 0; i < NUM_IPU_SUBDEVS; i++) {
intsd = &int_subdev[i];
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 9088c4b720a3..4cc6a7462ae2 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -841,7 +841,7 @@ find_pipeline_entity(struct media_entity *start, u32 grp_id,
if (sd->grp_id & grp_id)
return &sd->entity;
} else if (buftype && is_media_entity_v4l2_video_device(start)) {
- vfd = media_entity_to_video_device(pad->entity);
+ vfd = media_entity_to_video_device(start);
if (buftype == vfd->queue->type)
return &vfd->entity;
}
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 4d124a86b358..11861191324a 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -136,9 +136,15 @@ struct imx_media_dev {
/* master video device list */
struct list_head vdev_list;
+ /* IPUs this media driver control, valid after subdevs bound */
+ struct ipu_soc *ipu[2];
+
/* for async subdev registration */
struct v4l2_async_notifier notifier;
+ /* IC scaler/CSC mem2mem video device */
+ struct imx_media_video_dev *m2m_vdev;
+
/* the IPU internal subdev's registered synchronously */
struct v4l2_subdev *sync_sd[2][NUM_IPU_SUBDEVS];
};
@@ -269,6 +275,12 @@ struct imx_media_buffer *
imx_media_capture_device_next_buf(struct imx_media_video_dev *vdev);
void imx_media_capture_device_error(struct imx_media_video_dev *vdev);
+/* imx-media-csc-scaler.c */
+struct imx_media_video_dev *
+imx_media_csc_scaler_device_init(struct imx_media_dev *dev);
+int imx_media_csc_scaler_device_register(struct imx_media_video_dev *vdev);
+void imx_media_csc_scaler_device_unregister(struct imx_media_video_dev *vdev);
+
/* subdev group ids */
#define IMX_MEDIA_GRP_ID_CSI2 BIT(8)
#define IMX_MEDIA_GRP_ID_CSI BIT(9)
diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c
index f29e28df36ed..bfa4b254c4e4 100644
--- a/drivers/staging/media/imx/imx6-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx6-mipi-csi2.c
@@ -243,7 +243,7 @@ static int __maybe_unused csi2_dphy_wait_ulp(struct csi2_dev *csi2)
}
/* Waits for low-power LP-11 state on data and clock lanes. */
-static int csi2_dphy_wait_stopstate(struct csi2_dev *csi2)
+static void csi2_dphy_wait_stopstate(struct csi2_dev *csi2)
{
u32 mask, reg;
int ret;
@@ -254,11 +254,9 @@ static int csi2_dphy_wait_stopstate(struct csi2_dev *csi2)
ret = readl_poll_timeout(csi2->base + CSI2_PHY_STATE, reg,
(reg & mask) == mask, 0, 500000);
if (ret) {
- v4l2_err(&csi2->sd, "LP-11 timeout, phy_state = 0x%08x\n", reg);
- return ret;
+ v4l2_warn(&csi2->sd, "LP-11 wait timeout, likely a sensor driver bug, expect capture failures.\n");
+ v4l2_warn(&csi2->sd, "phy_state = 0x%08x\n", reg);
}
-
- return 0;
}
/* Wait for active clock on the clock lane. */
@@ -316,9 +314,7 @@ static int csi2_start(struct csi2_dev *csi2)
csi2_enable(csi2, true);
/* Step 5 */
- ret = csi2_dphy_wait_stopstate(csi2);
- if (ret)
- goto err_assert_reset;
+ csi2_dphy_wait_stopstate(csi2);
/* Step 6 */
ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1);
diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c
index 500b4c08d967..bfd6b5fbf484 100644
--- a/drivers/staging/media/imx/imx7-media-csi.c
+++ b/drivers/staging/media/imx/imx7-media-csi.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * V4L2 Capture CSI Subdev for Freescale i.MX7 SOC
+ * V4L2 Capture CSI Subdev for Freescale i.MX6UL/L / i.MX7 SOC
*
* Copyright (c) 2019 Linaro Ltd
*
@@ -765,6 +765,7 @@ static int imx7_csi_configure(struct imx7_csi *csi)
struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix;
__u32 in_code = csi->format_mbus[IMX7_CSI_PAD_SINK].code;
u32 cr1, cr18;
+ int width = out_pix->width;
if (out_pix->field == V4L2_FIELD_INTERLACED) {
imx7_csi_deinterlace_enable(csi, true);
@@ -774,15 +775,27 @@ static int imx7_csi_configure(struct imx7_csi *csi)
imx7_csi_buf_stride_set(csi, 0);
}
- imx7_csi_set_imagpara(csi, out_pix->width, out_pix->height);
+ cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+ if (!csi->is_csi2) {
+ if (out_pix->pixelformat == V4L2_PIX_FMT_UYVY ||
+ out_pix->pixelformat == V4L2_PIX_FMT_YUYV)
+ width *= 2;
+
+ imx7_csi_set_imagpara(csi, width, out_pix->height);
+
+ cr18 |= (BIT_BASEADDR_SWITCH_EN | BIT_BASEADDR_SWITCH_SEL |
+ BIT_BASEADDR_CHG_ERR_EN);
+ imx7_csi_reg_write(csi, cr18, CSI_CSICR18);
- if (!csi->is_csi2)
return 0;
+ }
+
+ imx7_csi_set_imagpara(csi, width, out_pix->height);
cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
cr1 &= ~BIT_GCLK_MODE;
- cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
cr18 &= BIT_MIPI_DATA_FORMAT_MASK;
cr18 |= BIT_DATA_FROM_MIPI;
@@ -817,11 +830,9 @@ static void imx7_csi_enable(struct imx7_csi *csi)
{
imx7_csi_sw_reset(csi);
- if (csi->is_csi2) {
- imx7_csi_dmareq_rff_enable(csi);
- imx7_csi_hw_enable_irq(csi);
- imx7_csi_hw_enable(csi);
- }
+ imx7_csi_dmareq_rff_enable(csi);
+ imx7_csi_hw_enable_irq(csi);
+ imx7_csi_hw_enable(csi);
}
static void imx7_csi_disable(struct imx7_csi *csi)
@@ -1194,10 +1205,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
}
csi->irq = platform_get_irq(pdev, 0);
- if (csi->irq < 0) {
- dev_err(dev, "Missing platform resources data\n");
+ if (csi->irq < 0)
return csi->irq;
- }
csi->regbase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(csi->regbase))
@@ -1302,6 +1311,7 @@ static int imx7_csi_remove(struct platform_device *pdev)
static const struct of_device_id imx7_csi_of_match[] = {
{ .compatible = "fsl,imx7-csi" },
+ { .compatible = "fsl,imx6ul-csi" },
{ },
};
MODULE_DEVICE_TABLE(of, imx7_csi_of_match);
diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c
index d1cdf011c8f1..73d8354e618c 100644
--- a/drivers/staging/media/imx/imx7-mipi-csis.c
+++ b/drivers/staging/media/imx/imx7-mipi-csis.c
@@ -975,10 +975,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
return PTR_ERR(state->regs);
state->irq = platform_get_irq(pdev, 0);
- if (state->irq < 0) {
- dev_err(dev, "Failed to get irq\n");
+ if (state->irq < 0)
return state->irq;
- }
ret = mipi_csis_clk_get(state);
if (ret < 0)
diff --git a/drivers/staging/media/ipu3/ipu3-tables.h b/drivers/staging/media/ipu3/ipu3-tables.h
index a1bf3286f380..9f719c48b432 100644
--- a/drivers/staging/media/ipu3/ipu3-tables.h
+++ b/drivers/staging/media/ipu3/ipu3-tables.h
@@ -4,6 +4,8 @@
#ifndef __IPU3_TABLES_H
#define __IPU3_TABLES_H
+#include <linux/bitops.h>
+
#include "ipu3-abi.h"
#define IMGU_BDS_GRANULARITY 32 /* Downscaling granularity */
@@ -12,7 +14,7 @@
#define IMGU_SCALER_DOWNSCALE_4TAPS_LEN 128
#define IMGU_SCALER_DOWNSCALE_2TAPS_LEN 64
-#define IMGU_SCALER_FP ((u32)1 << 31) /* 1.0 in fixed point */
+#define IMGU_SCALER_FP BIT(31) /* 1.0 in fixed point */
#define IMGU_XNR3_VMEM_LUT_LEN 16
diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c
index a7372395a101..06a61f31ca50 100644
--- a/drivers/staging/media/ipu3/ipu3.c
+++ b/drivers/staging/media/ipu3/ipu3.c
@@ -778,8 +778,7 @@ out:
static int __maybe_unused imgu_resume(struct device *dev)
{
- struct pci_dev *pci_dev = to_pci_dev(dev);
- struct imgu_device *imgu = pci_get_drvdata(pci_dev);
+ struct imgu_device *imgu = dev_get_drvdata(dev);
int r = 0;
unsigned int pipe;
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
index 3a21a8cec799..95102a4bdc62 100644
--- a/drivers/staging/media/meson/vdec/esparser.c
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -301,10 +301,8 @@ int esparser_init(struct platform_device *pdev, struct amvdec_core *core)
int irq;
irq = platform_get_irq_byname(pdev, "esparser");
- if (irq < 0) {
- dev_err(dev, "Failed getting ESPARSER IRQ from dtb\n");
+ if (irq < 0)
return irq;
- }
ret = devm_request_irq(dev, irq, esparser_isr, IRQF_SHARED,
"esparserirq", core);
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index c8be1db532ab..1a966cb2f3a6 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -1276,7 +1276,6 @@ static int iss_probe(struct platform_device *pdev)
/* Interrupt */
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
- dev_err(iss->dev, "No IRQ resource\n");
ret = -ENODEV;
goto error_iss;
}
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index c307707480f7..54144dc9f509 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -31,61 +31,61 @@
static struct iss_format_info formats[] = {
{ MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
- V4L2_PIX_FMT_GREY, 8, "Greyscale 8 bpp", },
+ V4L2_PIX_FMT_GREY, 8, },
{ MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10,
MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8,
- V4L2_PIX_FMT_Y10, 10, "Greyscale 10 bpp", },
+ V4L2_PIX_FMT_Y10, 10, },
{ MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10,
MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8,
- V4L2_PIX_FMT_Y12, 12, "Greyscale 12 bpp", },
+ V4L2_PIX_FMT_Y12, 12, },
{ MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
- V4L2_PIX_FMT_SBGGR8, 8, "BGGR Bayer 8 bpp", },
+ V4L2_PIX_FMT_SBGGR8, 8, },
{ MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
- V4L2_PIX_FMT_SGBRG8, 8, "GBRG Bayer 8 bpp", },
+ V4L2_PIX_FMT_SGBRG8, 8, },
{ MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
- V4L2_PIX_FMT_SGRBG8, 8, "GRBG Bayer 8 bpp", },
+ V4L2_PIX_FMT_SGRBG8, 8, },
{ MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
- V4L2_PIX_FMT_SRGGB8, 8, "RGGB Bayer 8 bpp", },
+ V4L2_PIX_FMT_SRGGB8, 8, },
{ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
MEDIA_BUS_FMT_SGRBG10_1X10, 0,
- V4L2_PIX_FMT_SGRBG10DPCM8, 8, "GRBG Bayer 10 bpp DPCM8", },
+ V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
{ MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10,
MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8,
- V4L2_PIX_FMT_SBGGR10, 10, "BGGR Bayer 10 bpp", },
+ V4L2_PIX_FMT_SBGGR10, 10, },
{ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10,
MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8,
- V4L2_PIX_FMT_SGBRG10, 10, "GBRG Bayer 10 bpp", },
+ V4L2_PIX_FMT_SGBRG10, 10, },
{ MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10,
MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8,
- V4L2_PIX_FMT_SGRBG10, 10, "GRBG Bayer 10 bpp", },
+ V4L2_PIX_FMT_SGRBG10, 10, },
{ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10,
MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8,
- V4L2_PIX_FMT_SRGGB10, 10, "RGGB Bayer 10 bpp", },
+ V4L2_PIX_FMT_SRGGB10, 10, },
{ MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10,
MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8,
- V4L2_PIX_FMT_SBGGR12, 12, "BGGR Bayer 12 bpp", },
+ V4L2_PIX_FMT_SBGGR12, 12, },
{ MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10,
MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8,
- V4L2_PIX_FMT_SGBRG12, 12, "GBRG Bayer 12 bpp", },
+ V4L2_PIX_FMT_SGBRG12, 12, },
{ MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10,
MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8,
- V4L2_PIX_FMT_SGRBG12, 12, "GRBG Bayer 12 bpp", },
+ V4L2_PIX_FMT_SGRBG12, 12, },
{ MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10,
MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8,
- V4L2_PIX_FMT_SRGGB12, 12, "RGGB Bayer 12 bpp", },
+ V4L2_PIX_FMT_SRGGB12, 12, },
{ MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16,
MEDIA_BUS_FMT_UYVY8_1X16, 0,
- V4L2_PIX_FMT_UYVY, 16, "YUV 4:2:2 (UYVY)", },
+ V4L2_PIX_FMT_UYVY, 16, },
{ MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16,
MEDIA_BUS_FMT_YUYV8_1X16, 0,
- V4L2_PIX_FMT_YUYV, 16, "YUV 4:2:2 (YUYV)", },
+ V4L2_PIX_FMT_YUYV, 16, },
{ MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8,
MEDIA_BUS_FMT_YUYV8_1_5X8, 0,
- V4L2_PIX_FMT_NV12, 8, "YUV 4:2:0 (NV12)", },
+ V4L2_PIX_FMT_NV12, 8, },
};
const struct iss_format_info *
@@ -563,8 +563,6 @@ iss_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
if (index == 0) {
f->pixelformat = info->pixelformat;
- strscpy(f->description, info->description,
- sizeof(f->description));
return 0;
}
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index f22489edb562..8b3dd92021e1 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -36,7 +36,6 @@ struct v4l2_pix_format;
* shifted to be 8 bits per pixel. =0 if format is not shiftable.
* @pixelformat: V4L2 pixel format FCC identifier
* @bpp: Bits per pixel
- * @description: Human-readable format description
*/
struct iss_format_info {
u32 code;
@@ -45,7 +44,6 @@ struct iss_format_info {
u32 flavor;
u32 pixelformat;
unsigned int bpp;
- const char *description;
};
enum iss_pipeline_stream_state {
diff --git a/drivers/staging/media/soc_camera/soc_camera.c b/drivers/staging/media/soc_camera/soc_camera.c
index a6232dcd59bc..7b9448e3c9ba 100644
--- a/drivers/staging/media/soc_camera/soc_camera.c
+++ b/drivers/staging/media/soc_camera/soc_camera.c
@@ -869,8 +869,6 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
format = icd->user_formats[f->index].host_fmt;
- if (format->name)
- strscpy(f->description, format->name, sizeof(f->description));
f->pixelformat = format->fourcc;
return 0;
}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index 370937edfc14..2d3ea8b74dfd 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -29,47 +29,72 @@
static const struct cedrus_control cedrus_controls[] = {
{
- .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
- .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params),
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
+ },
.codec = CEDRUS_CODEC_MPEG2,
.required = true,
},
{
- .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
- .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization),
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
+ },
.codec = CEDRUS_CODEC_MPEG2,
.required = false,
},
{
- .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
- .elem_size = sizeof(struct v4l2_ctrl_h264_decode_params),
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
+ },
.codec = CEDRUS_CODEC_H264,
.required = true,
},
{
- .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
- .elem_size = sizeof(struct v4l2_ctrl_h264_slice_params),
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
+ },
.codec = CEDRUS_CODEC_H264,
.required = true,
},
{
- .id = V4L2_CID_MPEG_VIDEO_H264_SPS,
- .elem_size = sizeof(struct v4l2_ctrl_h264_sps),
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SPS,
+ },
.codec = CEDRUS_CODEC_H264,
.required = true,
},
{
- .id = V4L2_CID_MPEG_VIDEO_H264_PPS,
- .elem_size = sizeof(struct v4l2_ctrl_h264_pps),
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PPS,
+ },
.codec = CEDRUS_CODEC_H264,
.required = true,
},
{
- .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
- .elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix),
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
+ },
.codec = CEDRUS_CODEC_H264,
.required = true,
},
+ {
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE,
+ .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED,
+ .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED,
+ },
+ .codec = CEDRUS_CODEC_H264,
+ .required = false,
+ },
+ {
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE,
+ .max = V4L2_MPEG_VIDEO_H264_START_CODE_NONE,
+ .def = V4L2_MPEG_VIDEO_H264_START_CODE_NONE,
+ },
+ .codec = CEDRUS_CODEC_H264,
+ .required = false,
+ },
};
#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
@@ -106,12 +131,8 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
return -ENOMEM;
for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
- struct v4l2_ctrl_config cfg = {};
-
- cfg.elem_size = cedrus_controls[i].elem_size;
- cfg.id = cedrus_controls[i].id;
-
- ctrl = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+ ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg,
+ NULL);
if (hdl->error) {
v4l2_err(&dev->v4l2_dev,
"Failed to create new custom control\n");
@@ -178,7 +199,7 @@ static int cedrus_request_validate(struct media_request *req)
continue;
ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl,
- cedrus_controls[i].id);
+ cedrus_controls[i].cfg.id);
if (!ctrl_test) {
v4l2_info(&ctx->dev->v4l2_dev,
"Missing required codec control\n");
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 3f476d0fd981..2f017a651848 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -49,8 +49,7 @@ enum cedrus_h264_pic_type {
};
struct cedrus_control {
- u32 id;
- u32 elem_size;
+ struct v4l2_ctrl_config cfg;
enum cedrus_codec codec;
unsigned char required:1;
};
@@ -100,8 +99,6 @@ struct cedrus_ctx {
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl **ctrls;
- struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME];
-
union {
struct {
void *mv_col_buf;
@@ -187,7 +184,7 @@ static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx,
if (index < 0)
return 0;
- buf = ctx->dst_bufs[index];
+ buf = ctx->fh.m2m_ctx->cap_q_ctx.q.bufs[index];
return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0;
}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
index bdad87eb9d79..56ca4c9ad01c 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -46,7 +46,7 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
break;
- case V4L2_PIX_FMT_H264_SLICE_RAW:
+ case V4L2_PIX_FMT_H264_SLICE:
run.h264.decode_params = cedrus_find_control_data(ctx,
V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS);
run.h264.pps = cedrus_find_control_data(ctx,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index a30bb283f69f..d6a782703c9b 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -118,7 +118,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
if (buf_idx < 0)
continue;
- cedrus_buf = vb2_to_cedrus_buffer(ctx->dst_bufs[buf_idx]);
+ cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]);
position = cedrus_buf->codec.h264.position;
used_dpbs |= BIT(position);
@@ -193,7 +193,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
if (buf_idx < 0)
continue;
- ref_buf = to_vb2_v4l2_buffer(ctx->dst_bufs[buf_idx]);
+ ref_buf = to_vb2_v4l2_buffer(cap_q->bufs[buf_idx]);
cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf);
position = cedrus_buf->codec.h264.position;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
index c34aec7c6e40..a942cd9bed57 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -79,9 +79,6 @@ void cedrus_dst_format_set(struct cedrus_dev *dev,
reg = VE_PRIMARY_OUT_FMT_NV12;
cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg);
- reg = VE_CHROMA_BUF_LEN_SDRT(chroma_size / 2);
- cedrus_write(dev, VE_CHROMA_BUF_LEN, reg);
-
reg = chroma_size / 2;
cedrus_write(dev, VE_PRIMARY_CHROMA_BUF_LEN, reg);
@@ -160,11 +157,8 @@ int cedrus_hw_probe(struct cedrus_dev *dev)
dev->capabilities = variant->capabilities;
irq_dec = platform_get_irq(dev->pdev, 0);
- if (irq_dec <= 0) {
- dev_err(dev->dev, "Failed to get IRQ\n");
-
+ if (irq_dec <= 0)
return irq_dec;
- }
ret = devm_request_irq(dev->dev, irq_dec, cedrus_irq,
0, dev_name(dev->dev), dev);
if (ret) {
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
index 3e9931416e45..ddd29788d685 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -110,7 +110,7 @@
#define VE_DEC_MPEG_MBADDR (VE_ENGINE_DEC_MPEG + 0x10)
#define VE_DEC_MPEG_MBADDR_X(w) (((w) << 8) & GENMASK(15, 8))
-#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(0, 7))
+#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(7, 0))
#define VE_DEC_MPEG_CTRL (VE_ENGINE_DEC_MPEG + 0x14)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index e2b530b1a956..eeee3efd247b 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -38,7 +38,7 @@ static struct cedrus_format cedrus_formats[] = {
.directions = CEDRUS_DECODE_SRC,
},
{
- .pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW,
+ .pixelformat = V4L2_PIX_FMT_H264_SLICE,
.directions = CEDRUS_DECODE_SRC,
},
{
@@ -104,7 +104,7 @@ static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
switch (pix_fmt->pixelformat) {
case V4L2_PIX_FMT_MPEG2_SLICE:
- case V4L2_PIX_FMT_H264_SLICE_RAW:
+ case V4L2_PIX_FMT_H264_SLICE:
/* Zero bytes per line for encoded source. */
bytesperline = 0;
@@ -411,26 +411,6 @@ static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state)
}
}
-static int cedrus_buf_init(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
-
- if (!V4L2_TYPE_IS_OUTPUT(vq->type))
- ctx->dst_bufs[vb->index] = vb;
-
- return 0;
-}
-
-static void cedrus_buf_cleanup(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
-
- if (!V4L2_TYPE_IS_OUTPUT(vq->type))
- ctx->dst_bufs[vb->index] = NULL;
-}
-
static int cedrus_buf_out_validate(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -469,7 +449,7 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
ctx->current_codec = CEDRUS_CODEC_MPEG2;
break;
- case V4L2_PIX_FMT_H264_SLICE_RAW:
+ case V4L2_PIX_FMT_H264_SLICE:
ctx->current_codec = CEDRUS_CODEC_H264;
break;
@@ -517,8 +497,6 @@ static void cedrus_buf_request_complete(struct vb2_buffer *vb)
static struct vb2_ops cedrus_qops = {
.queue_setup = cedrus_queue_setup,
.buf_prepare = cedrus_buf_prepare,
- .buf_init = cedrus_buf_init,
- .buf_cleanup = cedrus_buf_cleanup,
.buf_queue = cedrus_buf_queue,
.buf_out_validate = cedrus_buf_out_validate,
.buf_request_complete = cedrus_buf_request_complete,
diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig
index 2e7f644ae591..ba49ea50b8c0 100644
--- a/drivers/staging/media/tegra-vde/Kconfig
+++ b/drivers/staging/media/tegra-vde/Kconfig
@@ -3,7 +3,7 @@ config TEGRA_VDE
tristate "NVIDIA Tegra Video Decoder Engine driver"
depends on ARCH_TEGRA || COMPILE_TEST
select DMA_SHARED_BUFFER
- select IOMMU_IOVA if IOMMU_SUPPORT
+ select IOMMU_IOVA if (IOMMU_SUPPORT || COMPILE_TEST)
select SRAM
help
Say Y here to enable support for the NVIDIA Tegra video decoder
diff --git a/drivers/staging/most/cdev/cdev.c b/drivers/staging/most/cdev/cdev.c
index d0cc0b746107..724d098aeef0 100644
--- a/drivers/staging/most/cdev/cdev.c
+++ b/drivers/staging/most/cdev/cdev.c
@@ -463,10 +463,8 @@ static int comp_probe(struct most_interface *iface, int channel_id,
spin_lock_init(&c->unlink);
INIT_KFIFO(c->fifo);
retval = kfifo_alloc(&c->fifo, cfg->num_buffers, GFP_KERNEL);
- if (retval) {
- pr_info("failed to alloc channel kfifo");
+ if (retval)
goto err_del_cdev_and_free_channel;
- }
init_waitqueue_head(&c->wq);
mutex_init(&c->io_mutex);
spin_lock_irqsave(&ch_list_lock, cl_flags);
diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c
index b9841adb7181..8e9a0b67c6ed 100644
--- a/drivers/staging/most/core.c
+++ b/drivers/staging/most/core.c
@@ -303,7 +303,8 @@ static ssize_t set_datatype_show(struct device *dev,
for (i = 0; i < ARRAY_SIZE(ch_data_type); i++) {
if (c->cfg.data_type & ch_data_type[i].most_ch_data_type)
- return snprintf(buf, PAGE_SIZE, "%s", ch_data_type[i].name);
+ return snprintf(buf, PAGE_SIZE, "%s",
+ ch_data_type[i].name);
}
return snprintf(buf, PAGE_SIZE, "unconfigured\n");
}
@@ -721,6 +722,7 @@ int most_add_link(char *mdev, char *mdev_ch, char *comp_name, char *link_name,
return link_channel_to_component(c, comp, link_name, comp_param);
}
+
/**
* remove_link_store - store function for remove_link attribute
* @drv: device driver
diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c
index 31fbc1a75b06..64c979155a49 100644
--- a/drivers/staging/most/dim2/dim2.c
+++ b/drivers/staging/most/dim2/dim2.c
@@ -129,25 +129,6 @@ bool dim2_sysfs_get_state_cb(void)
}
/**
- * dimcb_io_read - callback from HAL to read an I/O register
- * @ptr32: register address
- */
-u32 dimcb_io_read(u32 __iomem *ptr32)
-{
- return readl(ptr32);
-}
-
-/**
- * dimcb_io_write - callback from HAL to write value to an I/O register
- * @ptr32: register address
- * @value: value to write
- */
-void dimcb_io_write(u32 __iomem *ptr32, u32 value)
-{
- writel(value, ptr32);
-}
-
-/**
* dimcb_on_error - callback from HAL to report miscommunication between
* HDM and HAL
* @error_id: Error ID
@@ -797,7 +778,6 @@ static int dim2_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, AHB0_INT_IDX);
if (irq < 0) {
- dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq);
ret = irq;
goto err_shutdown_dim;
}
@@ -811,7 +791,6 @@ static int dim2_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, MLB_INT_IDX);
if (irq < 0) {
- dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq);
ret = irq;
goto err_shutdown_dim;
}
diff --git a/drivers/staging/most/dim2/hal.c b/drivers/staging/most/dim2/hal.c
index 699e02f83bd4..39e17a7d2f24 100644
--- a/drivers/staging/most/dim2/hal.c
+++ b/drivers/staging/most/dim2/hal.c
@@ -13,6 +13,7 @@
#include "reg.h"
#include <linux/stddef.h>
#include <linux/kernel.h>
+#include <linux/io.h>
/*
* Size factor for isochronous DBR buffer.
@@ -143,13 +144,13 @@ static void free_dbr(int offs, int size)
static void dim2_transfer_madr(u32 val)
{
- dimcb_io_write(&g.dim2->MADR, val);
+ writel(val, &g.dim2->MADR);
/* wait for transfer completion */
- while ((dimcb_io_read(&g.dim2->MCTL) & 1) != 1)
+ while ((readl(&g.dim2->MCTL) & 1) != 1)
continue;
- dimcb_io_write(&g.dim2->MCTL, 0); /* clear transfer complete */
+ writel(0, &g.dim2->MCTL); /* clear transfer complete */
}
static void dim2_clear_dbr(u16 addr, u16 size)
@@ -159,8 +160,8 @@ static void dim2_clear_dbr(u16 addr, u16 size)
u16 const end_addr = addr + size;
u32 const cmd = bit_mask(MADR_WNR_BIT) | bit_mask(MADR_TB_BIT);
- dimcb_io_write(&g.dim2->MCTL, 0); /* clear transfer complete */
- dimcb_io_write(&g.dim2->MDAT0, 0);
+ writel(0, &g.dim2->MCTL); /* clear transfer complete */
+ writel(0, &g.dim2->MDAT0);
for (; addr < end_addr; addr++)
dim2_transfer_madr(cmd | addr);
@@ -170,28 +171,28 @@ static u32 dim2_read_ctr(u32 ctr_addr, u16 mdat_idx)
{
dim2_transfer_madr(ctr_addr);
- return dimcb_io_read((&g.dim2->MDAT0) + mdat_idx);
+ return readl((&g.dim2->MDAT0) + mdat_idx);
}
static void dim2_write_ctr_mask(u32 ctr_addr, const u32 *mask, const u32 *value)
{
enum { MADR_WNR_BIT = 31 };
- dimcb_io_write(&g.dim2->MCTL, 0); /* clear transfer complete */
+ writel(0, &g.dim2->MCTL); /* clear transfer complete */
if (mask[0] != 0)
- dimcb_io_write(&g.dim2->MDAT0, value[0]);
+ writel(value[0], &g.dim2->MDAT0);
if (mask[1] != 0)
- dimcb_io_write(&g.dim2->MDAT1, value[1]);
+ writel(value[1], &g.dim2->MDAT1);
if (mask[2] != 0)
- dimcb_io_write(&g.dim2->MDAT2, value[2]);
+ writel(value[2], &g.dim2->MDAT2);
if (mask[3] != 0)
- dimcb_io_write(&g.dim2->MDAT3, value[3]);
+ writel(value[3], &g.dim2->MDAT3);
- dimcb_io_write(&g.dim2->MDWE0, mask[0]);
- dimcb_io_write(&g.dim2->MDWE1, mask[1]);
- dimcb_io_write(&g.dim2->MDWE2, mask[2]);
- dimcb_io_write(&g.dim2->MDWE3, mask[3]);
+ writel(mask[0], &g.dim2->MDWE0);
+ writel(mask[1], &g.dim2->MDWE1);
+ writel(mask[2], &g.dim2->MDWE2);
+ writel(mask[3], &g.dim2->MDWE3);
dim2_transfer_madr(bit_mask(MADR_WNR_BIT) | ctr_addr);
}
@@ -356,15 +357,13 @@ static void dim2_configure_channel(
dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1);
/* unmask interrupt for used channel, enable mlb_sys_int[0] interrupt */
- dimcb_io_write(&g.dim2->ACMR0,
- dimcb_io_read(&g.dim2->ACMR0) | bit_mask(ch_addr));
+ writel(readl(&g.dim2->ACMR0) | bit_mask(ch_addr), &g.dim2->ACMR0);
}
static void dim2_clear_channel(u8 ch_addr)
{
/* mask interrupt for used channel, disable mlb_sys_int[0] interrupt */
- dimcb_io_write(&g.dim2->ACMR0,
- dimcb_io_read(&g.dim2->ACMR0) & ~bit_mask(ch_addr));
+ writel(readl(&g.dim2->ACMR0) & ~bit_mask(ch_addr), &g.dim2->ACMR0);
dim2_clear_cat(AHB_CAT, ch_addr);
dim2_clear_adt(ch_addr);
@@ -373,7 +372,7 @@ static void dim2_clear_channel(u8 ch_addr)
dim2_clear_cdt(ch_addr);
/* clear channel status bit */
- dimcb_io_write(&g.dim2->ACSR0, bit_mask(ch_addr));
+ writel(bit_mask(ch_addr), &g.dim2->ACSR0);
}
/* -------------------------------------------------------------------------- */
@@ -471,7 +470,7 @@ static inline bool check_bytes_per_frame(u32 bytes_per_frame)
return true;
}
-static inline u16 norm_ctrl_async_buffer_size(u16 buf_size)
+u16 dim_norm_ctrl_async_buffer_size(u16 buf_size)
{
u16 const max_size = (u16)ADT1_CTRL_ASYNC_BD_MASK + 1u;
@@ -517,20 +516,20 @@ static inline u16 norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame)
static void dim2_cleanup(void)
{
/* disable MediaLB */
- dimcb_io_write(&g.dim2->MLBC0, false << MLBC0_MLBEN_BIT);
+ writel(false << MLBC0_MLBEN_BIT, &g.dim2->MLBC0);
dim2_clear_ctram();
/* disable mlb_int interrupt */
- dimcb_io_write(&g.dim2->MIEN, 0);
+ writel(0, &g.dim2->MIEN);
/* clear status for all dma channels */
- dimcb_io_write(&g.dim2->ACSR0, 0xFFFFFFFF);
- dimcb_io_write(&g.dim2->ACSR1, 0xFFFFFFFF);
+ writel(0xFFFFFFFF, &g.dim2->ACSR0);
+ writel(0xFFFFFFFF, &g.dim2->ACSR1);
/* mask interrupts for all channels */
- dimcb_io_write(&g.dim2->ACMR0, 0);
- dimcb_io_write(&g.dim2->ACMR1, 0);
+ writel(0, &g.dim2->ACMR0);
+ writel(0, &g.dim2->ACMR1);
}
static void dim2_initialize(bool enable_6pin, u8 mlb_clock)
@@ -538,23 +537,22 @@ static void dim2_initialize(bool enable_6pin, u8 mlb_clock)
dim2_cleanup();
/* configure and enable MediaLB */
- dimcb_io_write(&g.dim2->MLBC0,
- enable_6pin << MLBC0_MLBPEN_BIT |
- mlb_clock << MLBC0_MLBCLK_SHIFT |
- g.fcnt << MLBC0_FCNT_SHIFT |
- true << MLBC0_MLBEN_BIT);
+ writel(enable_6pin << MLBC0_MLBPEN_BIT |
+ mlb_clock << MLBC0_MLBCLK_SHIFT |
+ g.fcnt << MLBC0_FCNT_SHIFT |
+ true << MLBC0_MLBEN_BIT,
+ &g.dim2->MLBC0);
/* activate all HBI channels */
- dimcb_io_write(&g.dim2->HCMR0, 0xFFFFFFFF);
- dimcb_io_write(&g.dim2->HCMR1, 0xFFFFFFFF);
+ writel(0xFFFFFFFF, &g.dim2->HCMR0);
+ writel(0xFFFFFFFF, &g.dim2->HCMR1);
/* enable HBI */
- dimcb_io_write(&g.dim2->HCTL, bit_mask(HCTL_EN_BIT));
+ writel(bit_mask(HCTL_EN_BIT), &g.dim2->HCTL);
/* configure DMA */
- dimcb_io_write(&g.dim2->ACTL,
- ACTL_DMA_MODE_VAL_DMA_MODE_1 << ACTL_DMA_MODE_BIT |
- true << ACTL_SCE_BIT);
+ writel(ACTL_DMA_MODE_VAL_DMA_MODE_1 << ACTL_DMA_MODE_BIT |
+ true << ACTL_SCE_BIT, &g.dim2->ACTL);
}
static bool dim2_is_mlb_locked(void)
@@ -562,12 +560,12 @@ static bool dim2_is_mlb_locked(void)
u32 const mask0 = bit_mask(MLBC0_MLBLK_BIT);
u32 const mask1 = bit_mask(MLBC1_CLKMERR_BIT) |
bit_mask(MLBC1_LOCKERR_BIT);
- u32 const c1 = dimcb_io_read(&g.dim2->MLBC1);
+ u32 const c1 = readl(&g.dim2->MLBC1);
u32 const nda_mask = (u32)MLBC1_NDA_MASK << MLBC1_NDA_SHIFT;
- dimcb_io_write(&g.dim2->MLBC1, c1 & nda_mask);
- return (dimcb_io_read(&g.dim2->MLBC1) & mask1) == 0 &&
- (dimcb_io_read(&g.dim2->MLBC0) & mask0) != 0;
+ writel(c1 & nda_mask, &g.dim2->MLBC1);
+ return (readl(&g.dim2->MLBC1) & mask1) == 0 &&
+ (readl(&g.dim2->MLBC0) & mask0) != 0;
}
/* -------------------------------------------------------------------------- */
@@ -590,7 +588,7 @@ static inline bool service_channel(u8 ch_addr, u8 idx)
dim2_write_ctr_mask(ADT + ch_addr, mask, adt_w);
/* clear channel status bit */
- dimcb_io_write(&g.dim2->ACSR0, bit_mask(ch_addr));
+ writel(bit_mask(ch_addr), &g.dim2->ACSR0);
return true;
}
@@ -652,7 +650,7 @@ static bool channel_start(struct dim_channel *ch, u32 buf_addr, u16 buf_size)
return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE, "Bad buffer size");
if (ch->packet_length == 0 && ch->bytes_per_frame == 0 &&
- buf_size != norm_ctrl_async_buffer_size(buf_size))
+ buf_size != dim_norm_ctrl_async_buffer_size(buf_size))
return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE,
"Bad control/async buffer size");
@@ -776,13 +774,8 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx,
void dim_service_mlb_int_irq(void)
{
- dimcb_io_write(&g.dim2->MS0, 0);
- dimcb_io_write(&g.dim2->MS1, 0);
-}
-
-u16 dim_norm_ctrl_async_buffer_size(u16 buf_size)
-{
- return norm_ctrl_async_buffer_size(buf_size);
+ writel(0, &g.dim2->MS0);
+ writel(0, &g.dim2->MS1);
}
/**
@@ -829,7 +822,7 @@ u8 dim_init_async(struct dim_channel *ch, u8 is_tx, u16 ch_address,
if (is_tx && !g.atx_dbr.ch_addr) {
g.atx_dbr.ch_addr = ch->addr;
dbrcnt_init(ch->addr, ch->dbr_size);
- dimcb_io_write(&g.dim2->MIEN, bit_mask(20));
+ writel(bit_mask(20), &g.dim2->MIEN);
}
return ret;
@@ -896,7 +889,7 @@ u8 dim_destroy_channel(struct dim_channel *ch)
return DIM_ERR_DRIVER_NOT_INITIALIZED;
if (ch->addr == g.atx_dbr.ch_addr) {
- dimcb_io_write(&g.dim2->MIEN, 0);
+ writel(0, &g.dim2->MIEN);
g.atx_dbr.ch_addr = 0;
}
diff --git a/drivers/staging/most/dim2/hal.h b/drivers/staging/most/dim2/hal.h
index fca6c22de8a6..20531449acab 100644
--- a/drivers/staging/most/dim2/hal.h
+++ b/drivers/staging/most/dim2/hal.h
@@ -97,10 +97,6 @@ bool dim_enqueue_buffer(struct dim_channel *ch, u32 buffer_addr,
bool dim_detach_buffers(struct dim_channel *ch, u16 buffers_number);
-u32 dimcb_io_read(u32 __iomem *ptr32);
-
-void dimcb_io_write(u32 __iomem *ptr32, u32 value);
-
void dimcb_on_error(u8 error_id, const char *error_message);
#endif /* _DIM2_HAL_H */
diff --git a/drivers/staging/most/net/net.c b/drivers/staging/most/net/net.c
index aababdf2be12..26a31854c636 100644
--- a/drivers/staging/most/net/net.c
+++ b/drivers/staging/most/net/net.c
@@ -69,7 +69,7 @@ struct net_dev_context {
static struct list_head net_devices = LIST_HEAD_INIT(net_devices);
static struct mutex probe_disc_mt; /* ch->linked = true, most_nd_open */
-static struct spinlock list_lock; /* list_head, ch->linked = false, dev_hold */
+static DEFINE_SPINLOCK(list_lock); /* list_head, ch->linked = false, dev_hold */
static struct core_component comp;
static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo)
@@ -509,7 +509,6 @@ static int __init most_net_init(void)
{
int err;
- spin_lock_init(&list_lock);
mutex_init(&probe_disc_mt);
err = most_register_component(&comp);
if (err)
diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c
index 342f390d68b3..79817061fcfa 100644
--- a/drivers/staging/most/sound/sound.c
+++ b/drivers/staging/most/sound/sound.c
@@ -802,8 +802,11 @@ static int __init audio_init(void)
if (ret)
pr_err("Failed to register %s\n", comp.name);
ret = most_register_configfs_subsys(&comp);
- if (ret)
+ if (ret) {
pr_err("Failed to register %s configfs subsys\n", comp.name);
+ most_deregister_component(&comp);
+ }
+
return ret;
}
diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c
index 6f6e98ab0550..250af9fb704d 100644
--- a/drivers/staging/most/video/video.c
+++ b/drivers/staging/most/video/video.c
@@ -54,7 +54,7 @@ struct comp_fh {
};
static struct list_head video_devices = LIST_HEAD_INIT(video_devices);
-static struct spinlock list_lock;
+static DEFINE_SPINLOCK(list_lock);
static inline bool data_ready(struct most_video_dev *mdev)
{
@@ -538,7 +538,6 @@ static int __init comp_init(void)
{
int err;
- spin_lock_init(&list_lock);
err = most_register_component(&comp);
if (err)
return err;
diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c
index 60db06768c8a..d964642d95a3 100644
--- a/drivers/staging/mt7621-dma/mtk-hsdma.c
+++ b/drivers/staging/mt7621-dma/mtk-hsdma.c
@@ -675,10 +675,8 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
tasklet_init(&hsdma->task, mtk_hsdma_tasklet, (unsigned long)hsdma);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get irq\n");
+ if (irq < 0)
return -EINVAL;
- }
ret = devm_request_irq(&pdev->dev, irq, mtk_hsdma_irq,
0, dev_name(&pdev->dev), hsdma);
if (ret) {
diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c
index 89fa813142ab..6b98827da57f 100644
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
@@ -400,6 +400,7 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
err = of_pci_get_devfn(child);
if (err < 0) {
+ of_node_put(child);
dev_err(dev, "failed to parse devfn: %d\n", err);
return err;
}
@@ -407,8 +408,10 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
slot = PCI_SLOT(err);
err = mt7621_pcie_parse_port(pcie, child, slot);
- if (err)
+ if (err) {
+ of_node_put(child);
return err;
+ }
}
return 0;
@@ -614,17 +617,12 @@ static int mt7621_pcie_request_resources(struct mt7621_pcie *pcie,
struct list_head *res)
{
struct device *dev = pcie->dev;
- int err;
pci_add_resource_offset(res, &pcie->io, pcie->offset.io);
pci_add_resource_offset(res, &pcie->mem, pcie->offset.mem);
pci_add_resource(res, &pcie->busn);
- err = devm_request_pci_bus_resources(dev, res);
- if (err < 0)
- return err;
-
- return 0;
+ return devm_request_pci_bus_resources(dev, res);
}
static int mt7621_pcie_register_host(struct pci_host_bridge *host,
diff --git a/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c
index 9b52d44abef1..d0f06790d38f 100644
--- a/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c
+++ b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c
@@ -358,12 +358,15 @@ static int rt2880_pinmux_probe(struct platform_device *pdev)
gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
if (!ngpio || !gpiobase) {
dev_err(&pdev->dev, "failed to load chip info\n");
+ of_node_put(np);
return -EINVAL;
}
range = devm_kzalloc(p->dev, sizeof(*range), GFP_KERNEL);
- if (!range)
+ if (!range) {
+ of_node_put(np);
return -ENOMEM;
+ }
range->name = "pio";
range->npins = __be32_to_cpu(*ngpio);
range->base = __be32_to_cpu(*gpiobase);
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 08027a36e0bc..360ec0407740 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -767,7 +767,6 @@ static int tegra_nvec_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct nvec_chip *nvec;
struct nvec_msg *msg;
- struct resource *res;
void __iomem *base;
char get_firmware_version[] = { NVEC_CNTL, GET_FIRMWARE_VERSION },
unmute_speakers[] = { NVEC_OEM0, 0x10, 0x59, 0x95 },
@@ -790,16 +789,13 @@ static int tegra_nvec_probe(struct platform_device *pdev)
return -ENODEV;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
+ base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
nvec->irq = platform_get_irq(pdev, 0);
- if (nvec->irq < 0) {
- dev_err(dev, "no irq resource?\n");
+ if (nvec->irq < 0)
return -ENODEV;
- }
i2c_clk = devm_clk_get(dev, "div-clk");
if (IS_ERR(i2c_clk)) {
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index cd2b777073c4..a5321cc692c5 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -3512,7 +3512,7 @@ static const struct hc_driver octeon_hc_driver = {
.product_desc = "Octeon Host Controller",
.hcd_priv_size = sizeof(struct octeon_hcd),
.irq = octeon_usb_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2,
.start = octeon_usb_start,
.stop = octeon_usb_stop,
.urb_enqueue = octeon_usb_urb_enqueue,
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 8889494adf1f..cf8e9a23ebf9 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -784,7 +784,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED;
priv->port = CVMX_PIP_NUM_INPUT_PORTS;
priv->queue = -1;
- strcpy(dev->name, "pow%d");
+ strscpy(dev->name, "pow%d", sizeof(dev->name));
for (qos = 0; qos < 16; qos++)
skb_queue_head_init(&priv->tx_free_list[qos]);
dev->min_mtu = VLAN_ETH_ZLEN - mtu_overhead;
@@ -856,39 +856,39 @@ static int cvm_oct_probe(struct platform_device *pdev)
case CVMX_HELPER_INTERFACE_MODE_NPI:
dev->netdev_ops = &cvm_oct_npi_netdev_ops;
- strcpy(dev->name, "npi%d");
+ strscpy(dev->name, "npi%d", sizeof(dev->name));
break;
case CVMX_HELPER_INTERFACE_MODE_XAUI:
dev->netdev_ops = &cvm_oct_xaui_netdev_ops;
- strcpy(dev->name, "xaui%d");
+ strscpy(dev->name, "xaui%d", sizeof(dev->name));
break;
case CVMX_HELPER_INTERFACE_MODE_LOOP:
dev->netdev_ops = &cvm_oct_npi_netdev_ops;
- strcpy(dev->name, "loop%d");
+ strscpy(dev->name, "loop%d", sizeof(dev->name));
break;
case CVMX_HELPER_INTERFACE_MODE_SGMII:
priv->phy_mode = PHY_INTERFACE_MODE_SGMII;
dev->netdev_ops = &cvm_oct_sgmii_netdev_ops;
- strcpy(dev->name, "eth%d");
+ strscpy(dev->name, "eth%d", sizeof(dev->name));
break;
case CVMX_HELPER_INTERFACE_MODE_SPI:
dev->netdev_ops = &cvm_oct_spi_netdev_ops;
- strcpy(dev->name, "spi%d");
+ strscpy(dev->name, "spi%d", sizeof(dev->name));
break;
case CVMX_HELPER_INTERFACE_MODE_GMII:
priv->phy_mode = PHY_INTERFACE_MODE_GMII;
dev->netdev_ops = &cvm_oct_rgmii_netdev_ops;
- strcpy(dev->name, "eth%d");
+ strscpy(dev->name, "eth%d", sizeof(dev->name));
break;
case CVMX_HELPER_INTERFACE_MODE_RGMII:
dev->netdev_ops = &cvm_oct_rgmii_netdev_ops;
- strcpy(dev->name, "eth%d");
+ strscpy(dev->name, "eth%d", sizeof(dev->name));
cvm_set_rgmii_delay(priv, interface,
port_index);
break;
diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO
index fe09efbc7f77..d8296f2ae872 100644
--- a/drivers/staging/olpc_dcon/TODO
+++ b/drivers/staging/olpc_dcon/TODO
@@ -8,10 +8,6 @@ TODO:
internals, but isn't properly integrated, is not the correct solution.
- see if vx855 gpio API can be made similar enough to cs5535 so we can
share more code
- - convert all uses of the old GPIO API from <linux/gpio.h> to the
- GPIO descriptor API in <linux/gpio/consumer.h> and look up GPIO
- lines from device tree, ACPI or board files, board files should
- use <linux/gpio/machine.h>
- allow simultaneous XO-1 and XO-1.5 support
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt
index 21cffdb86ecf..4a0d34b4ad37 100644
--- a/drivers/staging/pi433/Documentation/pi433.txt
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -14,7 +14,7 @@ until something gets received terminates the read request.
The driver supports on the fly reloading of the hardware fifo of the rf
chip, thus enabling for much longer telegrams than the hardware fifo size.
-Discription of driver operation
+Description of driver operation
===============================
a) transmission
diff --git a/drivers/staging/ralink-gdma/ralink-gdma.c b/drivers/staging/ralink-gdma/ralink-gdma.c
index 5854551d0a52..900424db9b97 100644
--- a/drivers/staging/ralink-gdma/ralink-gdma.c
+++ b/drivers/staging/ralink-gdma/ralink-gdma.c
@@ -826,10 +826,8 @@ static int gdma_dma_probe(struct platform_device *pdev)
tasklet_init(&dma_dev->task, gdma_dma_tasklet, (unsigned long)dma_dev);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get irq\n");
+ if (irq < 0)
return -EINVAL;
- }
ret = devm_request_irq(&pdev->dev, irq, gdma_dma_irq,
0, dev_name(&pdev->dev), dma_dev);
if (ret) {
diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c
index a24b40761af2..815dfee11968 100644
--- a/drivers/staging/rtl8188eu/core/rtw_cmd.c
+++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c
@@ -1200,7 +1200,7 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
rtw_indicate_connect(padapter);
} else {
- pwlan = _rtw_alloc_network(pmlmepriv);
+ pwlan = rtw_alloc_network(pmlmepriv);
spin_lock_bh(&pmlmepriv->scanned_queue.lock);
if (!pwlan) {
pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c
index 51c3dd6d7ffb..02c476f45b33 100644
--- a/drivers/staging/rtl8188eu/core/rtw_efuse.c
+++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c
@@ -108,7 +108,7 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
/* 1. Read the first byte to check if efuse is empty!!! */
/* */
/* */
- rtemp8 = *(phymap+eFuse_Addr);
+ rtemp8 = *(phymap + eFuse_Addr);
if (rtemp8 != 0xFF) {
efuse_utilized++;
eFuse_Addr++;
@@ -124,10 +124,10 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
/* Check PG header for section num. */
if ((rtemp8 & 0x1F) == 0x0F) { /* extended header */
u1temp = (rtemp8 & 0xE0) >> 5;
- rtemp8 = *(phymap+eFuse_Addr);
+ rtemp8 = *(phymap + eFuse_Addr);
if ((rtemp8 & 0x0F) == 0x0F) {
eFuse_Addr++;
- rtemp8 = *(phymap+eFuse_Addr);
+ rtemp8 = *(phymap + eFuse_Addr);
if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E))
eFuse_Addr++;
@@ -147,13 +147,13 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
/* Check word enable condition in the section */
if (!(wren & 0x01)) {
- rtemp8 = *(phymap+eFuse_Addr);
+ rtemp8 = *(phymap + eFuse_Addr);
eFuse_Addr++;
efuse_utilized++;
eFuseWord[offset][i] = (rtemp8 & 0xff);
if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
break;
- rtemp8 = *(phymap+eFuse_Addr);
+ rtemp8 = *(phymap + eFuse_Addr);
eFuse_Addr++;
efuse_utilized++;
eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00);
@@ -165,7 +165,7 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
}
}
/* Read next PG header */
- rtemp8 = *(phymap+eFuse_Addr);
+ rtemp8 = *(phymap + eFuse_Addr);
if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
efuse_utilized++;
@@ -178,8 +178,8 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
/* */
for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) {
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
- efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff);
- efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff);
+ efuseTbl[(i * 8) + (j * 2)] = (eFuseWord[i][j] & 0xff);
+ efuseTbl[(i * 8) + ((j * 2) + 1)] = ((eFuseWord[i][j] >> 8) & 0xff);
}
}
@@ -187,7 +187,7 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
/* 4. Copy from Efuse map to output pointer memory!!! */
/* */
for (i = 0; i < _size_byte; i++)
- pbuf[i] = efuseTbl[_offset+i];
+ pbuf[i] = efuseTbl[_offset + i];
/* */
/* 5. Calculate Efuse utilization. */
@@ -218,16 +218,16 @@ static void efuse_read_phymap_from_txpktbuf(
u8 *pos = content;
if (bcnhead < 0) /* if not valid */
- bcnhead = usb_read8(adapter, REG_TDECTRL+1);
+ bcnhead = usb_read8(adapter, REG_TDECTRL + 1);
DBG_88E("%s bcnhead:%d\n", __func__, bcnhead);
usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
- dbg_addr = bcnhead*128/8; /* 8-bytes addressing */
+ dbg_addr = bcnhead * 128 / 8; /* 8-bytes addressing */
while (1) {
- usb_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i);
+ usb_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr + i);
usb_write8(adapter, REG_TXPKTBUF_DBG, 0);
start = jiffies;
@@ -246,34 +246,34 @@ static void efuse_read_phymap_from_txpktbuf(
u16 aaa;
lenc[0] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L);
- lenc[1] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L+1);
+ lenc[1] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L + 1);
aaabak = le16_to_cpup((__le16 *)lenc);
lenbak = le16_to_cpu(*((__le16 *)lenc));
aaa = le16_to_cpup((__le16 *)&lo32);
len = le16_to_cpu(*((__le16 *)&lo32));
- limit = min_t(u16, len-2, limit);
+ limit = min_t(u16, len - 2, limit);
DBG_88E("%s len:%u, lenbak:%u, aaa:%u, aaabak:%u\n", __func__, len, lenbak, aaa, aaabak);
- memcpy(pos, ((u8 *)&lo32)+2, (limit >= count+2) ? 2 : limit-count);
- count += (limit >= count+2) ? 2 : limit-count;
- pos = content+count;
+ memcpy(pos, ((u8 *)&lo32) + 2, (limit >= count + 2) ? 2 : limit - count);
+ count += (limit >= count + 2) ? 2 : limit - count;
+ pos = content + count;
} else {
- memcpy(pos, ((u8 *)&lo32), (limit >= count+4) ? 4 : limit-count);
- count += (limit >= count+4) ? 4 : limit-count;
- pos = content+count;
+ memcpy(pos, ((u8 *)&lo32), (limit >= count + 4) ? 4 : limit - count);
+ count += (limit >= count + 4) ? 4 : limit - count;
+ pos = content + count;
}
- if (limit > count && len-2 > count) {
- memcpy(pos, (u8 *)&hi32, (limit >= count+4) ? 4 : limit-count);
- count += (limit >= count+4) ? 4 : limit-count;
- pos = content+count;
+ if (limit > count && len - 2 > count) {
+ memcpy(pos, (u8 *)&hi32, (limit >= count + 4) ? 4 : limit - count);
+ count += (limit >= count + 4) ? 4 : limit - count;
+ pos = content + count;
}
- if (limit <= count || len-2 <= count)
+ if (limit <= count || len - 2 <= count)
break;
i++;
}
@@ -288,7 +288,7 @@ static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset
u8 physical_map[512];
u16 size = 512;
- usb_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
+ usb_write8(padapter, REG_TDECTRL + 1, txpktbuf_bndy);
memset(physical_map, 0xFF, 512);
usb_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
status = iol_execute(padapter, CMD_READ_EFUSE_MAP);
@@ -323,7 +323,7 @@ u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_e
efuse_OneByteWrite(pAdapter, start_addr++, data[1]);
efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0]);
- efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[1]);
+ efuse_OneByteRead(pAdapter, tmpaddr + 1, &tmpdata[1]);
if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
badworden &= (~BIT(0));
}
@@ -333,7 +333,7 @@ u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_e
efuse_OneByteWrite(pAdapter, start_addr++, data[3]);
efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[2]);
- efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[3]);
+ efuse_OneByteRead(pAdapter, tmpaddr + 1, &tmpdata[3]);
if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
badworden &= (~BIT(1));
}
@@ -343,7 +343,7 @@ u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_e
efuse_OneByteWrite(pAdapter, start_addr++, data[5]);
efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4]);
- efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[5]);
+ efuse_OneByteRead(pAdapter, tmpaddr + 1, &tmpdata[5]);
if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
badworden &= (~BIT(2));
}
@@ -353,7 +353,7 @@ u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_e
efuse_OneByteWrite(pAdapter, start_addr++, data[7]);
efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6]);
- efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[7]);
+ efuse_OneByteRead(pAdapter, tmpaddr + 1, &tmpdata[7]);
if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
badworden &= (~BIT(3));
}
@@ -371,7 +371,7 @@ static u16 Efuse_GetCurrentSize(struct adapter *pAdapter)
while (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) &&
AVAILABLE_EFUSE_ADDR(efuse_addr)) {
if (efuse_data != 0xFF) {
- if ((efuse_data&0x1F) == 0x0F) { /* extended header */
+ if ((efuse_data & 0x1F) == 0x0F) { /* extended header */
hoffset = efuse_data;
efuse_addr++;
efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data);
@@ -383,12 +383,12 @@ static u16 Efuse_GetCurrentSize(struct adapter *pAdapter)
hworden = efuse_data & 0x0F;
}
} else {
- hoffset = (efuse_data>>4) & 0x0F;
+ hoffset = (efuse_data >> 4) & 0x0F;
hworden = efuse_data & 0x0F;
}
word_cnts = Efuse_CalculateWordCnts(hworden);
/* read next header */
- efuse_addr = efuse_addr + (word_cnts*2)+1;
+ efuse_addr = efuse_addr + (word_cnts * 2) + 1;
} else {
break;
}
@@ -439,15 +439,15 @@ int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data)
continue;
}
} else {
- hoffset = (efuse_data>>4) & 0x0F;
+ hoffset = (efuse_data >> 4) & 0x0F;
hworden = efuse_data & 0x0F;
}
word_cnts = Efuse_CalculateWordCnts(hworden);
bDataEmpty = true;
if (hoffset == offset) {
- for (tmpidx = 0; tmpidx < word_cnts*2; tmpidx++) {
- if (efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx, &efuse_data)) {
+ for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) {
+ if (efuse_OneByteRead(pAdapter, efuse_addr + 1 + tmpidx, &efuse_data)) {
tmpdata[tmpidx] = efuse_data;
if (efuse_data != 0xff)
bDataEmpty = false;
@@ -456,11 +456,11 @@ int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data)
if (!bDataEmpty) {
ReadState = PG_STATE_DATA;
} else {/* read next header */
- efuse_addr = efuse_addr + (word_cnts*2)+1;
+ efuse_addr = efuse_addr + (word_cnts * 2) + 1;
ReadState = PG_STATE_HEADER;
}
} else {/* read next header */
- efuse_addr = efuse_addr + (word_cnts*2)+1;
+ efuse_addr = efuse_addr + (word_cnts * 2) + 1;
ReadState = PG_STATE_HEADER;
}
} else {
@@ -469,7 +469,7 @@ int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data)
} else if (ReadState & PG_STATE_DATA) {
/* Data section Read ------------- */
efuse_WordEnableDataRead(hworden, tmpdata, data);
- efuse_addr = efuse_addr + (word_cnts*2)+1;
+ efuse_addr = efuse_addr + (word_cnts * 2) + 1;
ReadState = PG_STATE_HEADER;
}
}
@@ -491,7 +491,7 @@ static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, st
if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata)) {
/* check if data exist */
- badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata);
+ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr + 1, pFixPkt->word_en, originaldata);
if (badworden != 0xf) { /* write fail */
PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata);
@@ -501,10 +501,10 @@ static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, st
else
efuse_addr = Efuse_GetCurrentSize(pAdapter);
} else {
- efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
+ efuse_addr = efuse_addr + (pFixPkt->word_cnts * 2) + 1;
}
} else {
- efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
+ efuse_addr = efuse_addr + (pFixPkt->word_cnts * 2) + 1;
}
*pAddr = efuse_addr;
return true;
@@ -601,7 +601,7 @@ static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuse
} else {
struct pgpkt fixPkt;
- fixPkt.offset = (tmp_header>>4) & 0x0F;
+ fixPkt.offset = (tmp_header >> 4) & 0x0F;
fixPkt.word_en = tmp_header & 0x0F;
fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr))
@@ -619,7 +619,7 @@ static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u
u32 PgWriteSuccess = 0;
badworden = 0x0f;
- badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data);
+ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr + 1, pTargetPkt->word_en, pTargetPkt->data);
if (badworden == 0x0F) {
/* write ok */
return true;
@@ -681,8 +681,8 @@ static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts,
bool ret = false;
u8 i, efuse_data;
- for (i = 0; i < (word_cnts*2); i++) {
- if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data) && (efuse_data != 0xFF))
+ for (i = 0; i < (word_cnts * 2); i++) {
+ if (efuse_OneByteRead(pAdapter, (startAddr + i), &efuse_data) && (efuse_data != 0xFF))
ret = true;
}
return ret;
@@ -721,7 +721,7 @@ static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u
}
} else {
cur_header = efuse_data;
- curPkt.offset = (cur_header>>4) & 0x0F;
+ curPkt.offset = (cur_header >> 4) & 0x0F;
curPkt.word_en = cur_header & 0x0F;
}
@@ -729,10 +729,10 @@ static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u
/* if same header is found but no data followed */
/* write some part of data followed by the header. */
if ((curPkt.offset == pTargetPkt->offset) &&
- (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1)) &&
+ (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr + 1)) &&
wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) {
/* Here to write partial data */
- badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data);
+ badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr + 1, matched_wden, pTargetPkt->data);
if (badworden != 0x0F) {
u32 PgWriteSuccess = 0;
/* if write fail on some words, write these bad words again */
@@ -746,13 +746,13 @@ static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u
}
/* partial write ok, update the target packet for later use */
for (i = 0; i < 4; i++) {
- if ((matched_wden & (0x1<<i)) == 0) /* this word has been written */
- pTargetPkt->word_en |= (0x1<<i); /* disable the word */
+ if ((matched_wden & (0x1 << i)) == 0) /* this word has been written */
+ pTargetPkt->word_en |= (0x1 << i); /* disable the word */
}
pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
}
/* read from next header */
- startAddr = startAddr + (curPkt.word_cnts*2) + 1;
+ startAddr = startAddr + (curPkt.word_cnts * 2) + 1;
} else {
/* not used header, 0xff */
*pAddr = startAddr;
@@ -763,20 +763,9 @@ static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u
return ret;
}
-static bool
-hal_EfusePgCheckAvailableAddr(
- struct adapter *pAdapter,
- u8 efuseType
- )
-{
- if (Efuse_GetCurrentSize(pAdapter) >= EFUSE_MAP_LEN_88E)
- return false;
- return true;
-}
-
static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt)
{
- memset((void *)pTargetPkt->data, 0xFF, sizeof(u8)*8);
+ memset((void *)pTargetPkt->data, 0xFF, sizeof(u8) * 8);
pTargetPkt->offset = offset;
pTargetPkt->word_en = word_en;
efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data);
@@ -789,7 +778,7 @@ bool Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pD
u16 startAddr = 0;
u8 efuseType = EFUSE_WIFI;
- if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType))
+ if (Efuse_GetCurrentSize(pAdapter) >= EFUSE_MAP_LEN_88E)
return false;
hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
@@ -826,13 +815,13 @@ u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data)
u8 tmpidx = 0;
u8 result;
- usb_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr & 0xff));
- usb_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) & 0x03)) |
- (usb_read8(pAdapter, EFUSE_CTRL+2) & 0xFC));
+ usb_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff));
+ usb_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
+ (usb_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC));
- usb_write8(pAdapter, EFUSE_CTRL+3, 0x72);/* read cmd */
+ usb_write8(pAdapter, EFUSE_CTRL + 3, 0x72);/* read cmd */
- while (!(0x80 & usb_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100))
+ while (!(0x80 & usb_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100))
tmpidx++;
if (tmpidx < 100) {
*data = usb_read8(pAdapter, EFUSE_CTRL);
@@ -849,15 +838,15 @@ u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data)
u8 tmpidx = 0;
u8 result;
- usb_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));
- usb_write8(pAdapter, EFUSE_CTRL+2,
- (usb_read8(pAdapter, EFUSE_CTRL+2) & 0xFC) |
- (u8)((addr>>8) & 0x03));
+ usb_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff));
+ usb_write8(pAdapter, EFUSE_CTRL + 2,
+ (usb_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC) |
+ (u8)((addr >> 8) & 0x03));
usb_write8(pAdapter, EFUSE_CTRL, data);/* data */
- usb_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */
+ usb_write8(pAdapter, EFUSE_CTRL + 3, 0xF2);/* write cmd */
- while ((0x80 & usb_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100))
+ while ((0x80 & usb_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100))
tmpidx++;
if (tmpidx < 100)
diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
index 28b3cdd10397..cc1b5438c04c 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
@@ -59,7 +59,7 @@ static u8 WIFI_OFDMRATES[] = {
int rtw_get_bit_value_from_ieee_value(u8 val)
{
- unsigned char dot11_rate_table[] = {
+ static const unsigned char dot11_rate_table[] = {
2, 4, 11, 22, 12, 18, 24, 36, 48,
72, 96, 108, 0}; /* last element must be zero!! */
int i = 0;
@@ -275,7 +275,7 @@ unsigned char *rtw_get_wpa_ie(unsigned char *pie, uint *wpa_ie_len, int limit)
uint len;
u16 val16;
__le16 le_tmp;
- unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
+ static const unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
u8 *pbuf = pie;
int limit_new = limit;
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
index d2f7a88e992e..1ec3b237212e 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -104,7 +104,7 @@ void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv)
}
}
-struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv)
+struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
/* _queue *free_queue) */
{
struct wlan_network *pnetwork;
@@ -119,7 +119,7 @@ struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv)
list_del_init(&pnetwork->list);
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("_rtw_alloc_network: ptr=%p\n", &pnetwork->list));
+ ("rtw_alloc_network: ptr=%p\n", &pnetwork->list));
pnetwork->network_type = 0;
pnetwork->fixed = false;
pnetwork->last_scanned = jiffies;
@@ -272,11 +272,6 @@ u8 *rtw_get_beacon_interval_from_ie(u8 *ie)
return ie + 8;
}
-static struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
-{
- return _rtw_alloc_network(pmlmepriv);
-}
-
int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork)
{
int ret = true;
@@ -827,7 +822,7 @@ void rtw_indicate_disconnect(struct adapter *padapter)
inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted)
{
- rtw_os_indicate_scan_done(padapter, aborted);
+ indicate_wx_scan_complete_event(padapter);
}
static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, struct wlan_network *pnetwork)
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index 6f3c03201f64..18dc9fc1c04a 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -4854,7 +4854,7 @@ u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf)
}
rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type));
- /* Set_NETYPE0_MSR(padapter, type); */
+ /* Set_MSR(padapter, type); */
return H2C_SUCCESS;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
index 9caf7041ad60..d4278361e002 100644
--- a/drivers/staging/rtl8188eu/core/rtw_recv.c
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -145,8 +145,8 @@ int rtw_free_recvframe(struct recv_frame *precvframe,
int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue)
{
- list_del_init(&(precvframe->list));
- list_add_tail(&(precvframe->list), get_list_head(queue));
+ list_del_init(&precvframe->list);
+ list_add_tail(&precvframe->list, get_list_head(queue));
return _SUCCESS;
}
@@ -219,7 +219,7 @@ static int recvframe_chkmic(struct adapter *adapter,
struct security_priv *psecuritypriv = &adapter->securitypriv;
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]);
@@ -1373,11 +1373,7 @@ static struct recv_frame *recvframe_defrag(struct adapter *adapter,
/* append to first fragment frame's tail (if privacy frame, pull the ICV) */
skb_trim(prframe->pkt, prframe->pkt->len - prframe->attrib.icv_len);
- /* memcpy */
- memcpy(skb_tail_pointer(prframe->pkt), pnfhdr->pkt->data,
- pnfhdr->pkt->len);
-
- skb_put(prframe->pkt, pnfhdr->pkt->len);
+ skb_put_data(prframe->pkt, pnfhdr->pkt->data, pnfhdr->pkt->len);
prframe->attrib.icv_len = pnfhdr->attrib.icv_len;
plist = plist->next;
@@ -1500,7 +1496,7 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe)
struct rx_pkt_attrib *pattrib;
struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT];
struct recv_priv *precvpriv = &padapter->recvpriv;
- struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue);
+ struct __queue *pfree_recv_queue = &precvpriv->free_recv_queue;
nr_subframes = 0;
pattrib = &prframe->attrib;
diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c
index 2f90f60f1681..435c0fbec54a 100644
--- a/drivers/staging/rtl8188eu/core/rtw_security.c
+++ b/drivers/staging/rtl8188eu/core/rtw_security.c
@@ -87,29 +87,28 @@ static u8 crc32_reverseBit(u8 data)
static void crc32_init(void)
{
- if (bcrc32initialized == 1) {
+ int i, j;
+ u32 c;
+ u8 *p = (u8 *)&c, *p1;
+ u8 k;
+
+ if (bcrc32initialized == 1)
return;
- } else {
- int i, j;
- u32 c;
- u8 *p = (u8 *)&c, *p1;
- u8 k;
-
- c = 0x12340000;
-
- for (i = 0; i < 256; ++i) {
- k = crc32_reverseBit((u8)i);
- for (c = ((u32)k) << 24, j = 8; j > 0; --j)
- c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1);
- p1 = (u8 *)&crc32_table[i];
-
- p1[0] = crc32_reverseBit(p[3]);
- p1[1] = crc32_reverseBit(p[2]);
- p1[2] = crc32_reverseBit(p[1]);
- p1[3] = crc32_reverseBit(p[0]);
- }
- bcrc32initialized = 1;
+
+ c = 0x12340000;
+
+ for (i = 0; i < 256; ++i) {
+ k = crc32_reverseBit((u8)i);
+ for (c = ((u32)k) << 24, j = 8; j > 0; --j)
+ c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1);
+ p1 = (u8 *)&crc32_table[i];
+
+ p1[0] = crc32_reverseBit(p[3]);
+ p1[1] = crc32_reverseBit(p[2]);
+ p1[2] = crc32_reverseBit(p[1]);
+ p1[3] = crc32_reverseBit(p[0]);
}
+ bcrc32initialized = 1;
}
static __le32 getcrc32(u8 *buf, int len)
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
index 7bfc5b7c2757..c985b1468d41 100644
--- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -270,14 +270,9 @@ void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable)
rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode));
}
-static void Set_NETYPE0_MSR(struct adapter *padapter, u8 type)
-{
- rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
-}
-
void Set_MSR(struct adapter *padapter, u8 type)
{
- Set_NETYPE0_MSR(padapter, type);
+ rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
}
inline u8 rtw_get_oper_ch(struct adapter *adapter)
@@ -1179,15 +1174,10 @@ void Update_RA_Entry(struct adapter *padapter, u32 mac_id)
rtw_hal_update_ra_mask(padapter, mac_id, 0);
}
-static void enable_rate_adaptive(struct adapter *padapter, u32 mac_id)
-{
- Update_RA_Entry(padapter, mac_id);
-}
-
void set_sta_rate(struct adapter *padapter, struct sta_info *psta)
{
/* rate adaptive */
- enable_rate_adaptive(padapter, psta->mac_id);
+ Update_RA_Entry(padapter, psta->mac_id);
}
/* Update RRSR and Rate for USERATE */
@@ -1476,8 +1466,3 @@ void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext)
{
rtw_hal_set_hwreg(padapter, HW_VAR_CORRECT_TSF, NULL);
}
-
-void beacon_timing_control(struct adapter *padapter)
-{
- rtw_hal_bcn_related_reg_setting(padapter);
-}
diff --git a/drivers/staging/rtl8188eu/hal/bb_cfg.c b/drivers/staging/rtl8188eu/hal/bb_cfg.c
index 11e0bb9c67d7..51882858fcf0 100644
--- a/drivers/staging/rtl8188eu/hal/bb_cfg.c
+++ b/drivers/staging/rtl8188eu/hal/bb_cfg.c
@@ -653,7 +653,7 @@ static bool config_parafile(struct adapter *adapt)
bool rtl88eu_phy_bb_config(struct adapter *adapt)
{
- int rtstatus = true;
+ bool rtstatus;
u32 regval;
u8 crystal_cap;
diff --git a/drivers/staging/rtl8188eu/hal/rf_cfg.c b/drivers/staging/rtl8188eu/hal/rf_cfg.c
index 02aeb12c9870..47b1bf5a6143 100644
--- a/drivers/staging/rtl8188eu/hal/rf_cfg.c
+++ b/drivers/staging/rtl8188eu/hal/rf_cfg.c
@@ -218,11 +218,11 @@ static bool rtl88e_phy_config_rf_with_headerfile(struct adapter *adapt)
return true;
}
-static bool rf6052_conf_para(struct adapter *adapt)
+bool rtl88eu_phy_rf_config(struct adapter *adapt)
{
struct hal_data_8188e *hal_data = adapt->HalData;
u32 u4val = 0;
- bool rtstatus = true;
+ bool rtstatus;
struct bb_reg_def *pphyreg;
pphyreg = &hal_data->PHYRegDef[RF90_PATH_A];
@@ -246,13 +246,3 @@ static bool rf6052_conf_para(struct adapter *adapt)
return rtstatus;
}
-
-static bool rtl88e_phy_rf6052_config(struct adapter *adapt)
-{
- return rf6052_conf_para(adapt);
-}
-
-bool rtl88eu_phy_rf_config(struct adapter *adapt)
-{
- return rtl88e_phy_rf6052_config(adapt);
-}
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
index ac5552050752..16a57b31a439 100644
--- a/drivers/staging/rtl8188eu/hal/usb_halinit.c
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -183,14 +183,14 @@ static void _InitTxBufferBoundary(struct adapter *Adapter, u8 txpktbuf_bndy)
usb_write8(Adapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
usb_write8(Adapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy);
usb_write8(Adapter, REG_TRXFF_BNDY, txpktbuf_bndy);
- usb_write8(Adapter, REG_TDECTRL+1, txpktbuf_bndy);
+ usb_write8(Adapter, REG_TDECTRL + 1, txpktbuf_bndy);
}
static void _InitPageBoundary(struct adapter *Adapter)
{
/* RX Page Boundary */
/* */
- u16 rxff_bndy = MAX_RX_DMA_BUFFER_SIZE_88E-1;
+ u16 rxff_bndy = MAX_RX_DMA_BUFFER_SIZE_88E - 1;
usb_write16(Adapter, (REG_TRXFF_BNDY + 2), rxff_bndy);
}
@@ -504,7 +504,7 @@ static void usb_AggSettingRxUpdate(struct adapter *Adapter)
switch (haldata->UsbRxAggMode) {
case USB_RX_AGG_DMA:
usb_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount);
- usb_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, haldata->UsbRxAggPageTimeout);
+ usb_write8(Adapter, REG_RXDMA_AGG_PG_TH + 1, haldata->UsbRxAggPageTimeout);
break;
case USB_RX_AGG_USB:
usb_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount);
@@ -512,7 +512,7 @@ static void usb_AggSettingRxUpdate(struct adapter *Adapter)
break;
case USB_RX_AGG_MIX:
usb_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount);
- usb_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, (haldata->UsbRxAggPageTimeout & 0x1F));/* 0x280[12:8] */
+ usb_write8(Adapter, REG_RXDMA_AGG_PG_TH + 1, (haldata->UsbRxAggPageTimeout & 0x1F));/* 0x280[12:8] */
usb_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount);
usb_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout);
break;
@@ -569,9 +569,9 @@ static void _InitBeaconParameters(struct adapter *Adapter)
haldata->RegBcnCtrlVal = usb_read8(Adapter, REG_BCN_CTRL);
haldata->RegTxPause = usb_read8(Adapter, REG_TXPAUSE);
- haldata->RegFwHwTxQCtrl = usb_read8(Adapter, REG_FWHW_TXQ_CTRL+2);
- haldata->RegReg542 = usb_read8(Adapter, REG_TBTT_PROHIBIT+2);
- haldata->RegCR_1 = usb_read8(Adapter, REG_CR+1);
+ haldata->RegFwHwTxQCtrl = usb_read8(Adapter, REG_FWHW_TXQ_CTRL + 2);
+ haldata->RegReg542 = usb_read8(Adapter, REG_TBTT_PROHIBIT + 2);
+ haldata->RegCR_1 = usb_read8(Adapter, REG_CR + 1);
}
static void _BeaconFunctionEnable(struct adapter *Adapter,
@@ -579,7 +579,7 @@ static void _BeaconFunctionEnable(struct adapter *Adapter,
{
usb_write8(Adapter, REG_BCN_CTRL, (BIT(4) | BIT(3) | BIT(1)));
- usb_write8(Adapter, REG_RD_CTRL+1, 0x6F);
+ usb_write8(Adapter, REG_RD_CTRL + 1, 0x6F);
}
/* Set CCK and OFDM Block "ON" */
@@ -633,7 +633,7 @@ enum rt_rf_power_state RfOnOffDetect(struct adapter *adapt)
DBG_88E("pwrdown, 0x5c(BIT(7))=%02x\n", val8);
rfpowerstate = (val8 & BIT(7)) ? rf_off : rf_on;
} else { /* rf on/off */
- usb_write8(adapt, REG_MAC_PINMUX_CFG, usb_read8(adapt, REG_MAC_PINMUX_CFG)&~(BIT(3)));
+ usb_write8(adapt, REG_MAC_PINMUX_CFG, usb_read8(adapt, REG_MAC_PINMUX_CFG) & ~(BIT(3)));
val8 = usb_read8(adapt, REG_GPIO_IO_SEL);
DBG_88E("GPIO_IN=%02x\n", val8);
rfpowerstate = (val8 & BIT(3)) ? rf_on : rf_off;
@@ -770,7 +770,7 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
value8 = usb_read8(Adapter, REG_TX_RPT_CTRL);
usb_write8(Adapter, REG_TX_RPT_CTRL, (value8 | BIT(1) | BIT(0)));
/* Set MAX RPT MACID */
- usb_write8(Adapter, REG_TX_RPT_CTRL+1, 2);/* FOR sta mode ,0: bc/mc ,1:AP */
+ usb_write8(Adapter, REG_TX_RPT_CTRL + 1, 2);/* FOR sta mode ,0: bc/mc ,1:AP */
/* Tx RPT Timer. Unit: 32us */
usb_write16(Adapter, REG_TX_RPT_TIME, 0xCdf0);
@@ -827,10 +827,10 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
pwrctrlpriv->rf_pwrstate = rf_on;
/* enable Tx report. */
- usb_write8(Adapter, REG_FWHW_TXQ_CTRL+1, 0x0F);
+ usb_write8(Adapter, REG_FWHW_TXQ_CTRL + 1, 0x0F);
/* Suggested by SD1 pisa. Added by tynli. 2011.10.21. */
- usb_write8(Adapter, REG_EARLY_MODE_CONTROL+3, 0x01);/* Pretx_en, for WEP/TKIP SEC */
+ usb_write8(Adapter, REG_EARLY_MODE_CONTROL + 3, 0x01);/* Pretx_en, for WEP/TKIP SEC */
/* tynli_test_tx_report. */
usb_write16(Adapter, REG_TX_RPT_TIME, 0x3DF0);
@@ -880,7 +880,7 @@ static void CardDisableRTL8188EU(struct adapter *Adapter)
/* Stop Tx Report Timer. 0x4EC[Bit1]=b'0 */
val8 = usb_read8(Adapter, REG_TX_RPT_CTRL);
- usb_write8(Adapter, REG_TX_RPT_CTRL, val8&(~BIT(1)));
+ usb_write8(Adapter, REG_TX_RPT_CTRL, val8 & (~BIT(1)));
/* stop rx */
usb_write8(Adapter, REG_CR, 0x0);
@@ -894,9 +894,9 @@ static void CardDisableRTL8188EU(struct adapter *Adapter)
val8 = usb_read8(Adapter, REG_MCUFWDL);
if ((val8 & RAM_DL_SEL) && Adapter->bFWReady) { /* 8051 RAM code */
/* Reset MCU 0x2[10]=0. */
- val8 = usb_read8(Adapter, REG_SYS_FUNC_EN+1);
+ val8 = usb_read8(Adapter, REG_SYS_FUNC_EN + 1);
val8 &= ~BIT(2); /* 0x2[10], FEN_CPUEN */
- usb_write8(Adapter, REG_SYS_FUNC_EN+1, val8);
+ usb_write8(Adapter, REG_SYS_FUNC_EN + 1, val8);
}
/* reset MCU ready status */
@@ -905,17 +905,17 @@ static void CardDisableRTL8188EU(struct adapter *Adapter)
/* YJ,add,111212 */
/* Disable 32k */
val8 = usb_read8(Adapter, REG_32K_CTRL);
- usb_write8(Adapter, REG_32K_CTRL, val8&(~BIT(0)));
+ usb_write8(Adapter, REG_32K_CTRL, val8 & (~BIT(0)));
/* Card disable power action flow */
rtl88eu_pwrseqcmdparsing(Adapter, PWR_CUT_ALL_MSK,
Rtl8188E_NIC_DISABLE_FLOW);
/* Reset MCU IO Wrapper */
- val8 = usb_read8(Adapter, REG_RSV_CTRL+1);
- usb_write8(Adapter, REG_RSV_CTRL+1, (val8&(~BIT(3))));
- val8 = usb_read8(Adapter, REG_RSV_CTRL+1);
- usb_write8(Adapter, REG_RSV_CTRL+1, val8 | BIT(3));
+ val8 = usb_read8(Adapter, REG_RSV_CTRL + 1);
+ usb_write8(Adapter, REG_RSV_CTRL + 1, (val8 & (~BIT(3))));
+ val8 = usb_read8(Adapter, REG_RSV_CTRL + 1);
+ usb_write8(Adapter, REG_RSV_CTRL + 1, val8 | BIT(3));
/* YJ,test add, 111207. For Power Consumption. */
val8 = usb_read8(Adapter, GPIO_IN);
@@ -923,9 +923,9 @@ static void CardDisableRTL8188EU(struct adapter *Adapter)
usb_write8(Adapter, GPIO_IO_SEL, 0xFF);/* Reg0x46 */
val8 = usb_read8(Adapter, REG_GPIO_IO_SEL);
- usb_write8(Adapter, REG_GPIO_IO_SEL, (val8<<4));
- val8 = usb_read8(Adapter, REG_GPIO_IO_SEL+1);
- usb_write8(Adapter, REG_GPIO_IO_SEL+1, val8|0x0F);/* Reg0x43 */
+ usb_write8(Adapter, REG_GPIO_IO_SEL, (val8 << 4));
+ val8 = usb_read8(Adapter, REG_GPIO_IO_SEL + 1);
+ usb_write8(Adapter, REG_GPIO_IO_SEL + 1, val8 | 0x0F);/* Reg0x43 */
usb_write32(Adapter, REG_BB_PAD_CTRL, 0x00080808);/* set LNA ,TRSW,EX_PA Pin to output mode */
Adapter->HalData->bMacPwrCtrlOn = false;
Adapter->bFWReady = false;
@@ -1103,11 +1103,11 @@ static void ResumeTxBeacon(struct adapter *adapt)
/* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */
/* which should be read from register to a global variable. */
- usb_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl) | BIT(6));
+ usb_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl) | BIT(6));
haldata->RegFwHwTxQCtrl |= BIT(6);
- usb_write8(adapt, REG_TBTT_PROHIBIT+1, 0xff);
+ usb_write8(adapt, REG_TBTT_PROHIBIT + 1, 0xff);
haldata->RegReg542 |= BIT(0);
- usb_write8(adapt, REG_TBTT_PROHIBIT+2, haldata->RegReg542);
+ usb_write8(adapt, REG_TBTT_PROHIBIT + 2, haldata->RegReg542);
}
static void StopTxBeacon(struct adapter *adapt)
@@ -1117,11 +1117,11 @@ static void StopTxBeacon(struct adapter *adapt)
/* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */
/* which should be read from register to a global variable. */
- usb_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl) & (~BIT(6)));
+ usb_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl) & (~BIT(6)));
haldata->RegFwHwTxQCtrl &= (~BIT(6));
- usb_write8(adapt, REG_TBTT_PROHIBIT+1, 0x64);
+ usb_write8(adapt, REG_TBTT_PROHIBIT + 1, 0x64);
haldata->RegReg542 &= ~(BIT(0));
- usb_write8(adapt, REG_TBTT_PROHIBIT+2, haldata->RegReg542);
+ usb_write8(adapt, REG_TBTT_PROHIBIT + 2, haldata->RegReg542);
/* todo: CheckFwRsvdPageContent(Adapter); 2010.06.23. Added by tynli. */
}
@@ -1135,7 +1135,7 @@ static void hw_var_set_opmode(struct adapter *Adapter, u8 variable, u8 *val)
usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL) | BIT(4));
/* set net_type */
- val8 = usb_read8(Adapter, MSR)&0x0c;
+ val8 = usb_read8(Adapter, MSR) & 0x0c;
val8 |= mode;
usb_write8(Adapter, MSR, val8);
@@ -1176,7 +1176,7 @@ static void hw_var_set_opmode(struct adapter *Adapter, u8 variable, u8 *val)
/* enable BCN0 Function for if1 */
/* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */
- usb_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION | BIT(1)));
+ usb_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP | EN_BCN_FUNCTION | BIT(1)));
/* dis BCN1 ATIM WND if if2 is station */
usb_write8(Adapter, REG_BCN_CTRL_1, usb_read8(Adapter, REG_BCN_CTRL_1) | BIT(0));
@@ -1191,7 +1191,7 @@ static void hw_var_set_macaddr(struct adapter *Adapter, u8 variable, u8 *val)
reg_macid = REG_MACID;
for (idx = 0; idx < 6; idx++)
- usb_write8(Adapter, (reg_macid+idx), val[idx]);
+ usb_write8(Adapter, (reg_macid + idx), val[idx]);
}
static void hw_var_set_bssid(struct adapter *Adapter, u8 variable, u8 *val)
@@ -1202,7 +1202,7 @@ static void hw_var_set_bssid(struct adapter *Adapter, u8 variable, u8 *val)
reg_bssid = REG_BSSID;
for (idx = 0; idx < 6; idx++)
- usb_write8(Adapter, (reg_bssid+idx), val[idx]);
+ usb_write8(Adapter, (reg_bssid + idx), val[idx]);
}
static void hw_var_set_bcn_func(struct adapter *Adapter, u8 variable, u8 *val)
@@ -1214,7 +1214,7 @@ static void hw_var_set_bcn_func(struct adapter *Adapter, u8 variable, u8 *val)
if (*((u8 *)val))
usb_write8(Adapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT));
else
- usb_write8(Adapter, bcn_ctrl_reg, usb_read8(Adapter, bcn_ctrl_reg)&(~(EN_BCN_FUNCTION | EN_TXBCN_RPT)));
+ usb_write8(Adapter, bcn_ctrl_reg, usb_read8(Adapter, bcn_ctrl_reg) & (~(EN_BCN_FUNCTION | EN_TXBCN_RPT)));
}
void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
@@ -1228,7 +1228,7 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
{
u8 val8;
- val8 = usb_read8(Adapter, MSR)&0x0c;
+ val8 = usb_read8(Adapter, MSR) & 0x0c;
val8 |= *((u8 *)val);
usb_write8(Adapter, MSR, val8);
}
@@ -1274,8 +1274,8 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
BrateCfg |= 0x01; /* default enable 1M ACK rate */
/* Set RRSR rate table. */
usb_write8(Adapter, REG_RRSR, BrateCfg & 0xff);
- usb_write8(Adapter, REG_RRSR+1, (BrateCfg >> 8) & 0xff);
- usb_write8(Adapter, REG_RRSR+2, usb_read8(Adapter, REG_RRSR+2)&0xf0);
+ usb_write8(Adapter, REG_RRSR + 1, (BrateCfg >> 8) & 0xff);
+ usb_write8(Adapter, REG_RRSR + 2, usb_read8(Adapter, REG_RRSR + 2) & 0xf0);
/* Set RTS initial rate */
while (BrateCfg > 0x1) {
@@ -1298,27 +1298,27 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
- tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) - 1024; /* us */
+ tsf = pmlmeext->TSFValue - do_div(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval * 1024)) - 1024; /* us */
- if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
+ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE))
StopTxBeacon(Adapter);
/* disable related TSF function */
- usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL)&(~BIT(3)));
+ usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL) & (~BIT(3)));
usb_write32(Adapter, REG_TSFTR, tsf);
- usb_write32(Adapter, REG_TSFTR+4, tsf>>32);
+ usb_write32(Adapter, REG_TSFTR + 4, tsf >> 32);
/* enable related TSF function */
usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL) | BIT(3));
- if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
+ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE))
ResumeTxBeacon(Adapter);
}
break;
case HW_VAR_CHECK_BSSID:
if (*((u8 *)val)) {
- usb_write32(Adapter, REG_RCR, usb_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN);
+ usb_write32(Adapter, REG_RCR, usb_read32(Adapter, REG_RCR) | RCR_CBSSID_DATA | RCR_CBSSID_BCN);
} else {
u32 val32;
@@ -1357,19 +1357,19 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
if ((is_client_associated_to_ap(Adapter)) ||
- ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) {
+ ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) {
/* enable to rx data frame */
usb_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
/* enable update TSF */
- usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
- } else if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+ usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL) & (~BIT(4)));
+ } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
usb_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
/* enable update TSF */
- usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
+ usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL) & (~BIT(4)));
}
- usb_write32(Adapter, REG_RCR, usb_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN);
+ usb_write32(Adapter, REG_RCR, usb_read32(Adapter, REG_RCR) | RCR_CBSSID_BCN);
}
break;
case HW_VAR_MLME_JOIN:
@@ -1382,7 +1382,7 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
/* enable to rx data frame.Accept all data frame */
usb_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
- usb_write32(Adapter, REG_RCR, usb_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN);
+ usb_write32(Adapter, REG_RCR, usb_read32(Adapter, REG_RCR) | RCR_CBSSID_DATA | RCR_CBSSID_BCN);
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
RetryLimit = (haldata->CustomerID == RT_CID_CCX) ? 7 : 48;
@@ -1394,9 +1394,9 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
} else if (type == 2) {
/* sta add event call back */
/* enable update TSF */
- usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
+ usb_write8(Adapter, REG_BCN_CTRL, usb_read8(Adapter, REG_BCN_CTRL) & (~BIT(4)));
- if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE))
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE))
RetryLimit = 0x7;
}
usb_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT);
@@ -1432,21 +1432,21 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
case HW_VAR_RESP_SIFS:
/* RESP_SIFS for CCK */
usb_write8(Adapter, REG_R2T_SIFS, val[0]); /* SIFS_T2T_CCK (0x08) */
- usb_write8(Adapter, REG_R2T_SIFS+1, val[1]); /* SIFS_R2T_CCK(0x08) */
+ usb_write8(Adapter, REG_R2T_SIFS + 1, val[1]); /* SIFS_R2T_CCK(0x08) */
/* RESP_SIFS for OFDM */
usb_write8(Adapter, REG_T2T_SIFS, val[2]); /* SIFS_T2T_OFDM (0x0a) */
- usb_write8(Adapter, REG_T2T_SIFS+1, val[3]); /* SIFS_R2T_OFDM(0x0a) */
+ usb_write8(Adapter, REG_T2T_SIFS + 1, val[3]); /* SIFS_R2T_OFDM(0x0a) */
break;
case HW_VAR_ACK_PREAMBLE:
{
u8 regTmp;
u8 bShortPreamble = *((bool *)val);
/* Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */
- regTmp = (haldata->nCur40MhzPrimeSC)<<5;
+ regTmp = (haldata->nCur40MhzPrimeSC) << 5;
if (bShortPreamble)
regTmp |= 0x80;
- usb_write8(Adapter, REG_RRSR+2, regTmp);
+ usb_write8(Adapter, REG_RRSR + 2, regTmp);
}
break;
case HW_VAR_SEC_CFG:
@@ -1480,12 +1480,13 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
for (i = 0; i < CAM_CONTENT_COUNT; i++) {
/* filled id in CAM config 2 byte */
if (i == 0)
- ulContent |= (ucIndex & 0x03) | ((u16)(ulEncAlgo)<<2);
+ ulContent |= (ucIndex & 0x03) | ((u16)(ulEncAlgo) << 2);
else
ulContent = 0;
/* polling bit, and No Write enable, and address */
- ulCommand = CAM_CONTENT_COUNT*ucIndex+i;
- ulCommand = ulCommand | CAM_POLLINIG|CAM_WRITE;
+ ulCommand = CAM_CONTENT_COUNT * ucIndex + i;
+ ulCommand = ulCommand | CAM_POLLINIG |
+ CAM_WRITE;
/* write content 0 is equall to mark invalid */
usb_write32(Adapter, WCAMI, ulContent); /* delay_ms(40); */
usb_write32(Adapter, RWCAM, ulCommand); /* delay_ms(40); */
@@ -1589,13 +1590,13 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
FactorToSet = 0xf;
for (index = 0; index < 4; index++) {
- if ((pRegToSet[index] & 0xf0) > (FactorToSet<<4))
- pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet<<4);
+ if ((pRegToSet[index] & 0xf0) > (FactorToSet << 4))
+ pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet << 4);
if ((pRegToSet[index] & 0x0f) > FactorToSet)
pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet);
- usb_write8(Adapter, (REG_AGGLEN_LMT+index), pRegToSet[index]);
+ usb_write8(Adapter, (REG_AGGLEN_LMT + index), pRegToSet[index]);
}
}
}
@@ -1681,9 +1682,9 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
if (!pwrpriv->bkeepfwalive) {
/* RX DMA stop */
- usb_write32(Adapter, REG_RXPKT_NUM, (usb_read32(Adapter, REG_RXPKT_NUM)|RW_RELEASE_EN));
+ usb_write32(Adapter, REG_RXPKT_NUM, (usb_read32(Adapter, REG_RXPKT_NUM) | RW_RELEASE_EN));
do {
- if (!(usb_read32(Adapter, REG_RXPKT_NUM)&RXDMA_IDLE))
+ if (!(usb_read32(Adapter, REG_RXPKT_NUM) & RXDMA_IDLE))
break;
} while (trycnt--);
if (trycnt == 0)
@@ -1706,8 +1707,8 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
{
u8 maxMacid = *val;
- DBG_88E("### MacID(%d),Set Max Tx RPT MID(%d)\n", maxMacid, maxMacid+1);
- usb_write8(Adapter, REG_TX_RPT_CTRL+1, maxMacid+1);
+ DBG_88E("### MacID(%d),Set Max Tx RPT MID(%d)\n", maxMacid, maxMacid + 1);
+ usb_write8(Adapter, REG_TX_RPT_CTRL + 1, maxMacid + 1);
}
break;
case HW_VAR_H2C_MEDIA_STATUS_RPT:
@@ -1715,7 +1716,7 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
break;
case HW_VAR_BCN_VALID:
/* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, write 1 to clear, Clear by sw */
- usb_write8(Adapter, REG_TDECTRL+2, usb_read8(Adapter, REG_TDECTRL+2) | BIT(0));
+ usb_write8(Adapter, REG_TDECTRL + 2, usb_read8(Adapter, REG_TDECTRL + 2) | BIT(0));
break;
default:
break;
@@ -1733,7 +1734,7 @@ void rtw_hal_get_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
break;
case HW_VAR_BCN_VALID:
/* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */
- val[0] = (BIT(0) & usb_read8(Adapter, REG_TDECTRL+2)) ? true : false;
+ val[0] = (BIT(0) & usb_read8(Adapter, REG_TDECTRL + 2)) ? true : false;
break;
case HW_VAR_FWLPS_RF_ON:
{
@@ -1764,7 +1765,7 @@ void rtw_hal_get_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
*val = Adapter->HalData->bMacPwrCtrlOn;
break;
case HW_VAR_CHK_HI_QUEUE_EMPTY:
- *val = ((usb_read32(Adapter, REG_HGQ_INFORMATION)&0x0000ff00) == 0) ? true : false;
+ *val = ((usb_read32(Adapter, REG_HGQ_INFORMATION) & 0x0000ff00) == 0) ? true : false;
break;
default:
break;
@@ -1888,7 +1889,7 @@ void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level)
if (mac_id >= NUM_STA) /* CAM_SIZE */
return;
psta = pmlmeinfo->FW_sta_info[mac_id].psta;
- if (psta == NULL)
+ if (!psta)
return;
switch (mac_id) {
case 0:/* for infra mode */
@@ -1925,7 +1926,7 @@ void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level)
mask &= rate_bitmap;
- init_rate = get_highest_rate_idx(mask)&0x3f;
+ init_rate = get_highest_rate_idx(mask) & 0x3f;
ODM_RA_UpdateRateInfo_8188E(odmpriv, mac_id, raid, mask, shortGIrate);
@@ -1934,7 +1935,7 @@ void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level)
psta->init_rate = init_rate;
}
-void rtw_hal_bcn_related_reg_setting(struct adapter *adapt)
+void beacon_timing_control(struct adapter *adapt)
{
u32 value32;
struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv;
diff --git a/drivers/staging/rtl8188eu/include/hal8188e_phy_reg.h b/drivers/staging/rtl8188eu/include/hal8188e_phy_reg.h
index 53afcea21c96..bd915a1f2511 100644
--- a/drivers/staging/rtl8188eu/include/hal8188e_phy_reg.h
+++ b/drivers/staging/rtl8188eu/include/hal8188e_phy_reg.h
@@ -16,55 +16,10 @@
/* 5. Other definition for BB/RF R/W */
/* */
-
-/* */
-/* 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
-/* 1. Page1(0x100) */
-/* */
-#define rPMAC_Reset 0x100
-#define rPMAC_TxStart 0x104
-#define rPMAC_TxLegacySIG 0x108
-#define rPMAC_TxHTSIG1 0x10c
-#define rPMAC_TxHTSIG2 0x110
-#define rPMAC_PHYDebug 0x114
-#define rPMAC_TxPacketNum 0x118
-#define rPMAC_TxIdle 0x11c
-#define rPMAC_TxMACHeader0 0x120
-#define rPMAC_TxMACHeader1 0x124
-#define rPMAC_TxMACHeader2 0x128
-#define rPMAC_TxMACHeader3 0x12c
-#define rPMAC_TxMACHeader4 0x130
-#define rPMAC_TxMACHeader5 0x134
-#define rPMAC_TxDataType 0x138
-#define rPMAC_TxRandomSeed 0x13c
-#define rPMAC_CCKPLCPPreamble 0x140
-#define rPMAC_CCKPLCPHeader 0x144
-#define rPMAC_CCKCRC16 0x148
-#define rPMAC_OFDMRxCRC32OK 0x170
-#define rPMAC_OFDMRxCRC32Er 0x174
-#define rPMAC_OFDMRxParityEr 0x178
-#define rPMAC_OFDMRxCRC8Er 0x17c
-#define rPMAC_CCKCRxRC16Er 0x180
-#define rPMAC_CCKCRxRC32Er 0x184
-#define rPMAC_CCKCRxRC32OK 0x188
-#define rPMAC_TxStatus 0x18c
-
-/* 2. Page2(0x200) */
-/* The following two definition are only used for USB interface. */
-#define RF_BB_CMD_ADDR 0x02c0 /* RF/BB r/w cmd address. */
-#define RF_BB_CMD_DATA 0x02c4 /* RF/BB r/w cmd data. */
-
/* 3. Page8(0x800) */
#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC RF BW Setting */
-
-#define rFPGA0_TxInfo 0x804 /* Status report?? */
-#define rFPGA0_PSDFunction 0x808
-
#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */
-#define rFPGA0_RFTiming1 0x810 /* Useless now */
-#define rFPGA0_RFTiming2 0x814
-
#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */
#define rFPGA0_XA_HSSIParameter2 0x824
#define rFPGA0_XB_HSSIParameter1 0x828
@@ -73,9 +28,6 @@
#define rFPGA0_XA_LSSIParameter 0x840
#define rFPGA0_XB_LSSIParameter 0x844
-#define rFPGA0_RFWakeUpParameter 0x850 /* Useless now */
-#define rFPGA0_RFSleepUpParameter 0x854
-
#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */
#define rFPGA0_XCD_SwitchControl 0x85c
@@ -86,181 +38,63 @@
#define rFPGA0_XCD_RFInterfaceSW 0x874
#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */
-#define rFPGA0_XCD_RFParameter 0x87c
-
-/* Crystal cap setting RF-R/W protection for parameter4?? */
-#define rFPGA0_AnalogParameter1 0x880
-#define rFPGA0_AnalogParameter2 0x884
-#define rFPGA0_AnalogParameter3 0x888
-/* enable ad/da clock1 for dual-phy */
-#define rFPGA0_AdDaClockEn 0x888
-#define rFPGA0_AnalogParameter4 0x88c
#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */
#define rFPGA0_XB_LSSIReadBack 0x8a4
-#define rFPGA0_XC_LSSIReadBack 0x8a8
-#define rFPGA0_XD_LSSIReadBack 0x8ac
-#define rFPGA0_PSDReport 0x8b4 /* Useless now */
-/* Transceiver A HSPI Readback */
#define TransceiverA_HSPI_Readback 0x8b8
-/* Transceiver B HSPI Readback */
#define TransceiverB_HSPI_Readback 0x8bc
-/* Useless now RF Interface Readback Value */
#define rFPGA0_XAB_RFInterfaceRB 0x8e0
-#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */
/* 4. Page9(0x900) */
/* RF mode & OFDM TxSC RF BW Setting?? */
#define rFPGA1_RFMOD 0x900
-#define rFPGA1_TxBlock 0x904 /* Useless now */
-#define rFPGA1_DebugSelect 0x908 /* Useless now */
-#define rFPGA1_TxInfo 0x90c /* Useless now Status report */
-
/* 5. PageA(0xA00) */
/* Set Control channel to upper or lower - required only for 40MHz */
#define rCCK0_System 0xa00
-/* Disable init gain now Select RX path by RSSI */
-#define rCCK0_AFESetting 0xa04
-/* Disable init gain now Init gain */
-#define rCCK0_CCA 0xa08
-
-/* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold,
- * RX LNA Threshold useless now. Not the same as 90 series
- */
-#define rCCK0_RxAGC1 0xa0c
-#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */
-
-#define rCCK0_RxHP 0xa14
-
-/* Timing recovery & Channel estimation threshold */
-#define rCCK0_DSPParameter1 0xa18
-#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */
-
-#define rCCK0_TxFilter1 0xa20
-#define rCCK0_TxFilter2 0xa24
-#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */
-#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now */
-#define rCCK0_TRSSIReport 0xa50
-#define rCCK0_RxReport 0xa54 /* 0xa57 */
-#define rCCK0_FACounterLower 0xa5c /* 0xa5b */
-#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */
-
/* */
/* PageB(0xB00) */
/* */
-#define rPdp_AntA 0xb00
-#define rPdp_AntA_4 0xb04
-#define rConfig_Pmpd_AntA 0xb28
#define rConfig_AntA 0xb68
#define rConfig_AntB 0xb6c
-#define rPdp_AntB 0xb70
-#define rPdp_AntB_4 0xb74
-#define rConfig_Pmpd_AntB 0xb98
-#define rAPK 0xbd8
/* */
/* 6. PageC(0xC00) */
/* */
-#define rOFDM0_LSTF 0xc00
-
#define rOFDM0_TRxPathEnable 0xc04
#define rOFDM0_TRMuxPar 0xc08
-#define rOFDM0_TRSWIsolation 0xc0c
/* RxIQ DC offset, Rx digital filter, DC notch filter */
#define rOFDM0_XARxAFE 0xc10
#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imbalance matrix */
#define rOFDM0_XBRxAFE 0xc18
#define rOFDM0_XBRxIQImbalance 0xc1c
-#define rOFDM0_XCRxAFE 0xc20
-#define rOFDM0_XCRxIQImbalance 0xc24
-#define rOFDM0_XDRxAFE 0xc28
-#define rOFDM0_XDRxIQImbalance 0xc2c
-
-#define rOFDM0_RxDetector1 0xc30 /*PD,BW & SBD DM tune init gain*/
-#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */
-#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */
-#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */
#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */
-#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */
-#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */
#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */
#define rOFDM0_XAAGCCore1 0xc50 /* DIG */
#define rOFDM0_XAAGCCore2 0xc54
#define rOFDM0_XBAGCCore1 0xc58
#define rOFDM0_XBAGCCore2 0xc5c
-#define rOFDM0_XCAGCCore1 0xc60
-#define rOFDM0_XCAGCCore2 0xc64
-#define rOFDM0_XDAGCCore1 0xc68
-#define rOFDM0_XDAGCCore2 0xc6c
-#define rOFDM0_AGCParameter1 0xc70
-#define rOFDM0_AGCParameter2 0xc74
#define rOFDM0_AGCRSSITable 0xc78
-#define rOFDM0_HTSTFAGC 0xc7c
#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */
#define rOFDM0_XATxAFE 0xc84
#define rOFDM0_XBTxIQImbalance 0xc88
#define rOFDM0_XBTxAFE 0xc8c
-#define rOFDM0_XCTxIQImbalance 0xc90
#define rOFDM0_XCTxAFE 0xc94
-#define rOFDM0_XDTxIQImbalance 0xc98
#define rOFDM0_XDTxAFE 0xc9c
#define rOFDM0_RxIQExtAnta 0xca0
-#define rOFDM0_TxCoeff1 0xca4
-#define rOFDM0_TxCoeff2 0xca8
-#define rOFDM0_TxCoeff3 0xcac
-#define rOFDM0_TxCoeff4 0xcb0
-#define rOFDM0_TxCoeff5 0xcb4
-#define rOFDM0_TxCoeff6 0xcb8
-#define rOFDM0_RxHPParameter 0xce0
-#define rOFDM0_TxPseudoNoiseWgt 0xce4
-#define rOFDM0_FrameSync 0xcf0
-#define rOFDM0_DFSReport 0xcf4
-
/* */
/* 7. PageD(0xD00) */
/* */
#define rOFDM1_LSTF 0xd00
-#define rOFDM1_TRxPathEnable 0xd04
-
-#define rOFDM1_CFO 0xd08 /* No setting now */
-#define rOFDM1_CSI1 0xd10
-#define rOFDM1_SBD 0xd14
-#define rOFDM1_CSI2 0xd18
-#define rOFDM1_CFOTracking 0xd2c
-#define rOFDM1_TRxMesaure1 0xd34
-#define rOFDM1_IntfDet 0xd3c
-#define rOFDM1_PseudoNoiseStateAB 0xd50
-#define rOFDM1_PseudoNoiseStateCD 0xd54
-#define rOFDM1_RxPseudoNoiseWgt 0xd58
-
-#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */
-#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */
-#define rOFDM_PHYCounter3 0xda8 /* MCS not support */
-
-#define rOFDM_ShortCFOAB 0xdac /* No setting now */
-#define rOFDM_ShortCFOCD 0xdb0
-#define rOFDM_LongCFOAB 0xdb4
-#define rOFDM_LongCFOCD 0xdb8
-#define rOFDM_TailCFOAB 0xdbc
-#define rOFDM_TailCFOCD 0xdc0
-#define rOFDM_PWMeasure1 0xdc4
-#define rOFDM_PWMeasure2 0xdc8
-#define rOFDM_BWReport 0xdcc
-#define rOFDM_AGCReport 0xdd0
-#define rOFDM_RxSNR 0xdd4
-#define rOFDM_RxEVMCSI 0xdd8
-#define rOFDM_SIGReport 0xddc
-
/* */
/* 8. PageE(0xE00) */
@@ -292,10 +126,6 @@
#define rRx_IQK 0xe44
#define rIQK_AGC_Pts 0xe48
#define rIQK_AGC_Rsp 0xe4c
-#define rTx_IQK_Tone_B 0xe50
-#define rRx_IQK_Tone_B 0xe54
-#define rTx_IQK_PI_B 0xe58
-#define rRx_IQK_PI_B 0xe5c
#define rIQK_AGC_Cont 0xe60
#define rBlue_Tooth 0xe6c
@@ -311,17 +141,13 @@
#define rTx_Power_Before_IQK_A 0xe94
#define rTx_Power_After_IQK_A 0xe9c
-#define rRx_Power_Before_IQK_A 0xea0
#define rRx_Power_Before_IQK_A_2 0xea4
-#define rRx_Power_After_IQK_A 0xea8
#define rRx_Power_After_IQK_A_2 0xeac
#define rTx_Power_Before_IQK_B 0xeb4
#define rTx_Power_After_IQK_B 0xebc
-#define rRx_Power_Before_IQK_B 0xec0
#define rRx_Power_Before_IQK_B_2 0xec4
-#define rRx_Power_After_IQK_B 0xec8
#define rRx_Power_After_IQK_B_2 0xecc
#define rRx_OFDM 0xed0
@@ -332,751 +158,44 @@
#define rPMPD_ANAEN 0xeec
/* */
-/* 7. RF Register 0x00-0x2E (RF 8256) */
-/* RF-0222D 0x00-3F */
-/* */
-/* Zebra1 */
-#define rZebra1_HSSIEnable 0x0 /* Useless now */
-#define rZebra1_TRxEnable1 0x1
-#define rZebra1_TRxEnable2 0x2
-#define rZebra1_AGC 0x4
-#define rZebra1_ChargePump 0x5
-#define rZebra1_Channel 0x7 /* RF channel switch */
-
-/* endif */
-#define rZebra1_TxGain 0x8 /* Useless now */
-#define rZebra1_TxLPF 0x9
-#define rZebra1_RxLPF 0xb
-#define rZebra1_RxHPFCorner 0xc
-
-/* Zebra4 */
-#define rGlobalCtrl 0 /* Useless now */
-#define rRTL8256_TxLPF 19
-#define rRTL8256_RxLPF 11
-
-/* RTL8258 */
-#define rRTL8258_TxLPF 0x11 /* Useless now */
-#define rRTL8258_RxLPF 0x13
-#define rRTL8258_RSSILPF 0xa
-
-/* */
/* RL6052 Register definition */
/* */
#define RF_AC 0x00 /* */
-
-#define RF_IQADJ_G1 0x01 /* */
-#define RF_IQADJ_G2 0x02 /* */
-
-#define RF_POW_TRSW 0x05 /* */
-
-#define RF_GAIN_RX 0x06 /* */
-#define RF_GAIN_TX 0x07 /* */
-
-#define RF_TXM_IDAC 0x08 /* */
-#define RF_IPA_G 0x09 /* */
-#define RF_TXBIAS_G 0x0A
-#define RF_TXPA_AG 0x0B
-#define RF_IPA_A 0x0C /* */
-#define RF_TXBIAS_A 0x0D
-#define RF_BS_PA_APSET_G9_G11 0x0E
-#define RF_BS_IQGEN 0x0F /* */
-
-#define RF_MODE1 0x10 /* */
-#define RF_MODE2 0x11 /* */
-
-#define RF_RX_AGC_HP 0x12 /* */
-#define RF_TX_AGC 0x13 /* */
-#define RF_BIAS 0x14 /* */
-#define RF_IPA 0x15 /* */
-#define RF_TXBIAS 0x16
-#define RF_POW_ABILITY 0x17 /* */
#define RF_CHNLBW 0x18 /* RF channel and BW switch */
-#define RF_TOP 0x19 /* */
-
-#define RF_RX_G1 0x1A /* */
-#define RF_RX_G2 0x1B /* */
-
-#define RF_RX_BB2 0x1C /* */
-#define RF_RX_BB1 0x1D /* */
-
-#define RF_RCK1 0x1E /* */
-#define RF_RCK2 0x1F /* */
-
-#define RF_TX_G1 0x20 /* */
-#define RF_TX_G2 0x21 /* */
-#define RF_TX_G3 0x22 /* */
-
-#define RF_TX_BB1 0x23 /* */
-
-#define RF_T_METER_92D 0x42 /* */
#define RF_T_METER_88E 0x42 /* */
-#define RF_T_METER 0x24 /* */
-
-#define RF_SYN_G1 0x25 /* RF TX Power control */
-#define RF_SYN_G2 0x26 /* RF TX Power control */
-#define RF_SYN_G3 0x27 /* RF TX Power control */
-#define RF_SYN_G4 0x28 /* RF TX Power control */
-#define RF_SYN_G5 0x29 /* RF TX Power control */
-#define RF_SYN_G6 0x2A /* RF TX Power control */
-#define RF_SYN_G7 0x2B /* RF TX Power control */
-#define RF_SYN_G8 0x2C /* RF TX Power control */
-
#define RF_RCK_OS 0x30 /* RF TX PA control */
#define RF_TXPA_G1 0x31 /* RF TX PA control */
#define RF_TXPA_G2 0x32 /* RF TX PA control */
-#define RF_TXPA_G3 0x33 /* RF TX PA control */
-#define RF_TX_BIAS_A 0x35
-#define RF_TX_BIAS_D 0x36
-#define RF_LOBF_9 0x38
-#define RF_RXRF_A3 0x3C /* */
-#define RF_TRSW 0x3F
-
-#define RF_TXRF_A2 0x41
-#define RF_TXPA_G4 0x46
-#define RF_TXPA_A4 0x4B
-#define RF_0x52 0x52
#define RF_WE_LUT 0xEF
-
/* */
/* Bit Mask */
/* */
-/* 1. Page1(0x100) */
-#define bBBResetB 0x100 /* Useless now? */
-#define bGlobalResetB 0x200
-#define bOFDMTxStart 0x4
-#define bCCKTxStart 0x8
-#define bCRC32Debug 0x100
-#define bPMACLoopback 0x10
-#define bTxLSIG 0xffffff
-#define bOFDMTxRate 0xf
-#define bOFDMTxReserved 0x10
-#define bOFDMTxLength 0x1ffe0
-#define bOFDMTxParity 0x20000
-#define bTxHTSIG1 0xffffff
-#define bTxHTMCSRate 0x7f
-#define bTxHTBW 0x80
-#define bTxHTLength 0xffff00
-#define bTxHTSIG2 0xffffff
-#define bTxHTSmoothing 0x1
-#define bTxHTSounding 0x2
-#define bTxHTReserved 0x4
-#define bTxHTAggreation 0x8
-#define bTxHTSTBC 0x30
-#define bTxHTAdvanceCoding 0x40
-#define bTxHTShortGI 0x80
-#define bTxHTNumberHT_LTF 0x300
-#define bTxHTCRC8 0x3fc00
-#define bCounterReset 0x10000
-#define bNumOfOFDMTx 0xffff
-#define bNumOfCCKTx 0xffff0000
-#define bTxIdleInterval 0xffff
-#define bOFDMService 0xffff0000
-#define bTxMACHeader 0xffffffff
-#define bTxDataInit 0xff
-#define bTxHTMode 0x100
-#define bTxDataType 0x30000
-#define bTxRandomSeed 0xffffffff
-#define bCCKTxPreamble 0x1
-#define bCCKTxSFD 0xffff0000
-#define bCCKTxSIG 0xff
-#define bCCKTxService 0xff00
-#define bCCKLengthExt 0x8000
-#define bCCKTxLength 0xffff0000
-#define bCCKTxCRC16 0xffff
-#define bCCKTxStatus 0x1
-#define bOFDMTxStatus 0x2
-
-#define IS_BB_REG_OFFSET_92S(_Offset) \
- ((_Offset >= 0x800) && (_Offset <= 0xfff))
/* 2. Page8(0x800) */
#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */
-#define bJapanMode 0x2
-#define bCCKTxSC 0x30
#define bCCKEn 0x1000000
#define bOFDMEn 0x2000000
-#define bOFDMRxADCPhase 0x10000 /* Useless now */
-#define bOFDMTxDACPhase 0x40000
-#define bXATxAGC 0x3f
-
-#define bAntennaSelect 0x0300
-
-#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */
-#define bXCTxAGC 0xf000
-#define bXDTxAGC 0xf0000
-
-#define bPAStart 0xf0000000 /* Useless now */
-#define bTRStart 0x00f00000
-#define bRFStart 0x0000f000
-#define bBBStart 0x000000f0
-#define bBBCCKStart 0x0000000f
-#define bPAEnd 0xf /* Reg0x814 */
-#define bTREnd 0x0f000000
-#define bRFEnd 0x000f0000
-#define bCCAMask 0x000000f0 /* T2R */
-#define bR2RCCAMask 0x00000f00
-#define bHSSI_R2TDelay 0xf8000000
-#define bHSSI_T2RDelay 0xf80000
-#define bContTxHSSI 0x400 /* change gain at continue Tx */
-#define bIGFromCCK 0x200
-#define bAGCAddress 0x3f
-#define bRxHPTx 0x7000
-#define bRxHPT2R 0x38000
-#define bRxHPCCKIni 0xc0000
-#define bAGCTxCode 0xc00000
-#define bAGCRxCode 0x300000
-
-/* Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */
-#define b3WireDataLength 0x800
-#define b3WireAddressLength 0x400
-
-#define b3WireRFPowerDown 0x1 /* Useless now */
-#define b5GPAPEPolarity 0x40000000
-#define b2GPAPEPolarity 0x80000000
-#define bRFSW_TxDefaultAnt 0x3
-#define bRFSW_TxOptionAnt 0x30
-#define bRFSW_RxDefaultAnt 0x300
-#define bRFSW_RxOptionAnt 0x3000
-#define bRFSI_3WireData 0x1
-#define bRFSI_3WireClock 0x2
-#define bRFSI_3WireLoad 0x4
-#define bRFSI_3WireRW 0x8
-#define bRFSI_3Wire 0xf
-
-#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */
-
-#define bRFSI_TRSW 0x20 /* Useless now */
-#define bRFSI_TRSWB 0x40
-#define bRFSI_ANTSW 0x100
-#define bRFSI_ANTSWB 0x200
-#define bRFSI_PAPE 0x400
-#define bRFSI_PAPE5G 0x800
-#define bBandSelect 0x1
-#define bHTSIG2_GI 0x80
-#define bHTSIG2_Smoothing 0x01
-#define bHTSIG2_Sounding 0x02
-#define bHTSIG2_Aggreaton 0x08
-#define bHTSIG2_STBC 0x30
-#define bHTSIG2_AdvCoding 0x40
-#define bHTSIG2_NumOfHTLTF 0x300
-#define bHTSIG2_CRC8 0x3fc
-#define bHTSIG1_MCS 0x7f
-#define bHTSIG1_BandWidth 0x80
-#define bHTSIG1_HTLength 0xffff
-#define bLSIG_Rate 0xf
-#define bLSIG_Reserved 0x10
-#define bLSIG_Length 0x1fffe
-#define bLSIG_Parity 0x20
-#define bCCKRxPhase 0x4
-
#define bLSSIReadAddress 0x7f800000 /* T65 RF */
-
#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */
-
#define bLSSIReadBackData 0xfffff /* T65 RF */
-#define bLSSIReadOKFlag 0x1000 /* Useless now */
-#define bCCKSampleRate 0x8 /* 0: 44MHz, 1:88MHz */
-#define bRegulator0Standby 0x1
-#define bRegulatorPLLStandby 0x2
-#define bRegulator1Standby 0x4
-#define bPLLPowerUp 0x8
-#define bDPLLPowerUp 0x10
-#define bDA10PowerUp 0x20
-#define bAD7PowerUp 0x200
-#define bDA6PowerUp 0x2000
-#define bXtalPowerUp 0x4000
-#define b40MDClkPowerUP 0x8000
-#define bDA6DebugMode 0x20000
-#define bDA6Swing 0x380000
-
-/* Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */
-#define bADClkPhase 0x4000000
-
-#define b80MClkDelay 0x18000000 /* Useless */
-#define bAFEWatchDogEnable 0x20000000
-
-/* Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */
-#define bXtalCap01 0xc0000000
-#define bXtalCap23 0x3
-#define bXtalCap92x 0x0f000000
-#define bXtalCap 0x0f000000
-
-#define bIntDifClkEnable 0x400 /* Useless */
-#define bExtSigClkEnable 0x800
-#define bBandgapMbiasPowerUp 0x10000
-#define bAD11SHGain 0xc0000
-#define bAD11InputRange 0x700000
-#define bAD11OPCurrent 0x3800000
-#define bIPathLoopback 0x4000000
-#define bQPathLoopback 0x8000000
-#define bAFELoopback 0x10000000
-#define bDA10Swing 0x7e0
-#define bDA10Reverse 0x800
-#define bDAClkSource 0x1000
-#define bAD7InputRange 0x6000
-#define bAD7Gain 0x38000
-#define bAD7OutputCMMode 0x40000
-#define bAD7InputCMMode 0x380000
-#define bAD7Current 0xc00000
-#define bRegulatorAdjust 0x7000000
-#define bAD11PowerUpAtTx 0x1
-#define bDA10PSAtTx 0x10
-#define bAD11PowerUpAtRx 0x100
-#define bDA10PSAtRx 0x1000
-#define bCCKRxAGCFormat 0x200
-#define bPSDFFTSamplepPoint 0xc000
-#define bPSDAverageNum 0x3000
-#define bIQPathControl 0xc00
-#define bPSDFreq 0x3ff
-#define bPSDAntennaPath 0x30
-#define bPSDIQSwitch 0x40
-#define bPSDRxTrigger 0x400000
-#define bPSDTxTrigger 0x80000000
-#define bPSDSineToneScale 0x7f000000
-#define bPSDReport 0xffff
-
-/* 3. Page9(0x900) */
-#define bOFDMTxSC 0x30000000 /* Useless */
-#define bCCKTxOn 0x1
-#define bOFDMTxOn 0x2
-#define bDebugPage 0xfff /* reset debug page and HWord, LWord */
-#define bDebugItem 0xff /* reset debug page and LWord */
-#define bAntL 0x10
-#define bAntNonHT 0x100
-#define bAntHT1 0x1000
-#define bAntHT2 0x10000
-#define bAntHT1S1 0x100000
-#define bAntNonHTS1 0x1000000
-
-/* 4. PageA(0xA00) */
-#define bCCKBBMode 0x3 /* Useless */
-#define bCCKTxPowerSaving 0x80
-#define bCCKRxPowerSaving 0x40
-
#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 */
-#define bCCKScramble 0x8 /* Useless */
-#define bCCKAntDiversity 0x8000
-#define bCCKCarrierRecovery 0x4000
-#define bCCKTxRate 0x3000
-#define bCCKDCCancel 0x0800
-#define bCCKISICancel 0x0400
-#define bCCKMatchFilter 0x0200
-#define bCCKEqualizer 0x0100
-#define bCCKPreambleDetect 0x800000
-#define bCCKFastFalseCCA 0x400000
-#define bCCKChEstStart 0x300000
-#define bCCKCCACount 0x080000
-#define bCCKcs_lim 0x070000
-#define bCCKBistMode 0x80000000
-#define bCCKCCAMask 0x40000000
-#define bCCKTxDACPhase 0x4
-#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */
-#define bCCKr_cp_mode0 0x0100
-#define bCCKTxDCOffset 0xf0
-#define bCCKRxDCOffset 0xf
-#define bCCKCCAMode 0xc000
-#define bCCKFalseCS_lim 0x3f00
-#define bCCKCS_ratio 0xc00000
-#define bCCKCorgBit_sel 0x300000
-#define bCCKPD_lim 0x0f0000
-#define bCCKNewCCA 0x80000000
-#define bCCKRxHPofIG 0x8000
-#define bCCKRxIG 0x7f00
-#define bCCKLNAPolarity 0x800000
-#define bCCKRx1stGain 0x7f0000
-#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */
-#define bCCKRxAGCSatLevel 0x1f000000
-#define bCCKRxAGCSatCount 0xe0
-#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */
-#define bCCKFixedRxAGC 0x8000
-#define bCCKAntennaPolarity 0x2000
-#define bCCKTxFilterType 0x0c00
-#define bCCKRxAGCReportType 0x0300
-#define bCCKRxDAGCEn 0x80000000
-#define bCCKRxDAGCPeriod 0x20000000
-#define bCCKRxDAGCSatLevel 0x1f000000
-#define bCCKTimingRecovery 0x800000
-#define bCCKTxC0 0x3f0000
-#define bCCKTxC1 0x3f000000
-#define bCCKTxC2 0x3f
-#define bCCKTxC3 0x3f00
-#define bCCKTxC4 0x3f0000
-#define bCCKTxC5 0x3f000000
-#define bCCKTxC6 0x3f
-#define bCCKTxC7 0x3f00
-#define bCCKDebugPort 0xff0000
-#define bCCKDACDebug 0x0f000000
-#define bCCKFalseAlarmEnable 0x8000
-#define bCCKFalseAlarmRead 0x4000
-#define bCCKTRSSI 0x7f
-#define bCCKRxAGCReport 0xfe
-#define bCCKRxReport_AntSel 0x80000000
-#define bCCKRxReport_MFOff 0x40000000
-#define bCCKRxRxReport_SQLoss 0x20000000
-#define bCCKRxReport_Pktloss 0x10000000
-#define bCCKRxReport_Lockedbit 0x08000000
-#define bCCKRxReport_RateError 0x04000000
-#define bCCKRxReport_RxRate 0x03000000
-#define bCCKRxFACounterLower 0xff
-#define bCCKRxFACounterUpper 0xff000000
-#define bCCKRxHPAGCStart 0xe000
-#define bCCKRxHPAGCFinal 0x1c00
-#define bCCKRxFalseAlarmEnable 0x8000
-#define bCCKFACounterFreeze 0x4000
-#define bCCKTxPathSel 0x10000000
-#define bCCKDefaultRxPath 0xc000000
-#define bCCKOptionRxPath 0x3000000
-
-/* 5. PageC(0xC00) */
-#define bNumOfSTF 0x3 /* Useless */
-#define bShift_L 0xc0
-#define bGI_TH 0xc
-#define bRxPathA 0x1
-#define bRxPathB 0x2
-#define bRxPathC 0x4
-#define bRxPathD 0x8
-#define bTxPathA 0x1
-#define bTxPathB 0x2
-#define bTxPathC 0x4
-#define bTxPathD 0x8
-#define bTRSSIFreq 0x200
-#define bADCBackoff 0x3000
-#define bDFIRBackoff 0xc000
-#define bTRSSILatchPhase 0x10000
-#define bRxIDCOffset 0xff
-#define bRxQDCOffset 0xff00
-#define bRxDFIRMode 0x1800000
-#define bRxDCNFType 0xe000000
-#define bRXIQImb_A 0x3ff
-#define bRXIQImb_B 0xfc00
-#define bRXIQImb_C 0x3f0000
-#define bRXIQImb_D 0xffc00000
-#define bDC_dc_Notch 0x60000
-#define bRxNBINotch 0x1f000000
-#define bPD_TH 0xf
-#define bPD_TH_Opt2 0xc000
-#define bPWED_TH 0x700
-#define bIfMF_Win_L 0x800
-#define bPD_Option 0x1000
-#define bMF_Win_L 0xe000
-#define bBW_Search_L 0x30000
-#define bwin_enh_L 0xc0000
-#define bBW_TH 0x700000
-#define bED_TH2 0x3800000
-#define bBW_option 0x4000000
-#define bRatio_TH 0x18000000
-#define bWindow_L 0xe0000000
-#define bSBD_Option 0x1
-#define bFrame_TH 0x1c
-#define bFS_Option 0x60
-#define bDC_Slope_check 0x80
-#define bFGuard_Counter_DC_L 0xe00
-#define bFrame_Weight_Short 0x7000
-#define bSub_Tune 0xe00000
-#define bFrame_DC_Length 0xe000000
-#define bSBD_start_offset 0x30000000
-#define bFrame_TH_2 0x7
-#define bFrame_GI2_TH 0x38
-#define bGI2_Sync_en 0x40
-#define bSarch_Short_Early 0x300
-#define bSarch_Short_Late 0xc00
-#define bSarch_GI2_Late 0x70000
-#define bCFOAntSum 0x1
-#define bCFOAcc 0x2
-#define bCFOStartOffset 0xc
-#define bCFOLookBack 0x70
-#define bCFOSumWeight 0x80
-#define bDAGCEnable 0x10000
-#define bTXIQImb_A 0x3ff
-#define bTXIQImb_B 0xfc00
-#define bTXIQImb_C 0x3f0000
-#define bTXIQImb_D 0xffc00000
-#define bTxIDCOffset 0xff
-#define bTxQDCOffset 0xff00
-#define bTxDFIRMode 0x10000
-#define bTxPesudoNoiseOn 0x4000000
-#define bTxPesudoNoise_A 0xff
-#define bTxPesudoNoise_B 0xff00
-#define bTxPesudoNoise_C 0xff0000
-#define bTxPesudoNoise_D 0xff000000
-#define bCCADropOption 0x20000
-#define bCCADropThres 0xfff00000
-#define bEDCCA_H 0xf
-#define bEDCCA_L 0xf0
-#define bLambda_ED 0x300
-#define bRxInitialGain 0x7f
-#define bRxAntDivEn 0x80
-#define bRxAGCAddressForLNA 0x7f00
-#define bRxHighPowerFlow 0x8000
-#define bRxAGCFreezeThres 0xc0000
-#define bRxFreezeStep_AGC1 0x300000
-#define bRxFreezeStep_AGC2 0xc00000
-#define bRxFreezeStep_AGC3 0x3000000
-#define bRxFreezeStep_AGC0 0xc000000
-#define bRxRssi_Cmp_En 0x10000000
-#define bRxQuickAGCEn 0x20000000
-#define bRxAGCFreezeThresMode 0x40000000
-#define bRxOverFlowCheckType 0x80000000
-#define bRxAGCShift 0x7f
-#define bTRSW_Tri_Only 0x80
-#define bPowerThres 0x300
-#define bRxAGCEn 0x1
-#define bRxAGCTogetherEn 0x2
-#define bRxAGCMin 0x4
-#define bRxHP_Ini 0x7
-#define bRxHP_TRLNA 0x70
-#define bRxHP_RSSI 0x700
-#define bRxHP_BBP1 0x7000
-#define bRxHP_BBP2 0x70000
-#define bRxHP_BBP3 0x700000
-#define bRSSI_H 0x7f0000 /* threshold for high power */
-#define bRSSI_Gen 0x7f000000 /* threshold for ant diversity */
-#define bRxSettle_TRSW 0x7
-#define bRxSettle_LNA 0x38
-#define bRxSettle_RSSI 0x1c0
-#define bRxSettle_BBP 0xe00
-#define bRxSettle_RxHP 0x7000
-#define bRxSettle_AntSW_RSSI 0x38000
-#define bRxSettle_AntSW 0xc0000
-#define bRxProcessTime_DAGC 0x300000
-#define bRxSettle_HSSI 0x400000
-#define bRxProcessTime_BBPPW 0x800000
-#define bRxAntennaPowerShift 0x3000000
-#define bRSSITableSelect 0xc000000
-#define bRxHP_Final 0x7000000
-#define bRxHTSettle_BBP 0x7
-#define bRxHTSettle_HSSI 0x8
-#define bRxHTSettle_RxHP 0x70
-#define bRxHTSettle_BBPPW 0x80
-#define bRxHTSettle_Idle 0x300
-#define bRxHTSettle_Reserved 0x1c00
-#define bRxHTRxHPEn 0x8000
-#define bRxHTAGCFreezeThres 0x30000
-#define bRxHTAGCTogetherEn 0x40000
-#define bRxHTAGCMin 0x80000
-#define bRxHTAGCEn 0x100000
-#define bRxHTDAGCEn 0x200000
-#define bRxHTRxHP_BBP 0x1c00000
-#define bRxHTRxHP_Final 0xe0000000
-#define bRxPWRatioTH 0x3
-#define bRxPWRatioEn 0x4
-#define bRxMFHold 0x3800
-#define bRxPD_Delay_TH1 0x38
-#define bRxPD_Delay_TH2 0x1c0
-#define bRxPD_DC_COUNT_MAX 0x600
-#define bRxPD_Delay_TH 0x8000
-#define bRxProcess_Delay 0xf0000
-#define bRxSearchrange_GI2_Early 0x700000
-#define bRxFrame_Guard_Counter_L 0x3800000
-#define bRxSGI_Guard_L 0xc000000
-#define bRxSGI_Search_L 0x30000000
-#define bRxSGI_TH 0xc0000000
-#define bDFSCnt0 0xff
-#define bDFSCnt1 0xff00
-#define bDFSFlag 0xf0000
-#define bMFWeightSum 0x300000
-#define bMinIdxTH 0x7f000000
-#define bDAFormat 0x40000
-#define bTxChEmuEnable 0x01000000
-#define bTRSWIsolation_A 0x7f
-#define bTRSWIsolation_B 0x7f00
-#define bTRSWIsolation_C 0x7f0000
-#define bTRSWIsolation_D 0x7f000000
-#define bExtLNAGain 0x7c00
-
-/* 6. PageE(0xE00) */
-#define bSTBCEn 0x4 /* Useless */
-#define bAntennaMapping 0x10
-#define bNss 0x20
-#define bCFOAntSumD 0x200
-#define bPHYCounterReset 0x8000000
-#define bCFOReportGet 0x4000000
-#define bOFDMContinueTx 0x10000000
-#define bOFDMSingleCarrier 0x20000000
-#define bOFDMSingleTone 0x40000000
-#define bHTDetect 0x100
-#define bCFOEn 0x10000
-#define bCFOValue 0xfff00000
-#define bSigTone_Re 0x3f
-#define bSigTone_Im 0x7f00
-#define bCounter_CCA 0xffff
-#define bCounter_ParityFail 0xffff0000
-#define bCounter_RateIllegal 0xffff
-#define bCounter_CRC8Fail 0xffff0000
-#define bCounter_MCSNoSupport 0xffff
-#define bCounter_FastSync 0xffff
-#define bShortCFO 0xfff
-#define bShortCFOTLength 12 /* total */
-#define bShortCFOFLength 11 /* fraction */
-#define bLongCFO 0x7ff
-#define bLongCFOTLength 11
-#define bLongCFOFLength 11
-#define bTailCFO 0x1fff
-#define bTailCFOTLength 13
-#define bTailCFOFLength 12
-#define bmax_en_pwdB 0xffff
-#define bCC_power_dB 0xffff0000
-#define bnoise_pwdB 0xffff
-#define bPowerMeasTLength 10
-#define bPowerMeasFLength 3
-#define bRx_HT_BW 0x1
-#define bRxSC 0x6
-#define bRx_HT 0x8
-#define bNB_intf_det_on 0x1
-#define bIntf_win_len_cfg 0x30
-#define bNB_Intf_TH_cfg 0x1c0
-#define bRFGain 0x3f
-#define bTableSel 0x40
-#define bTRSW 0x80
-#define bRxSNR_A 0xff
-#define bRxSNR_B 0xff00
-#define bRxSNR_C 0xff0000
-#define bRxSNR_D 0xff000000
-#define bSNREVMTLength 8
-#define bSNREVMFLength 1
-#define bCSI1st 0xff
-#define bCSI2nd 0xff00
-#define bRxEVM1st 0xff0000
-#define bRxEVM2nd 0xff000000
-#define bSIGEVM 0xff
-#define bPWDB 0xff00
-#define bSGIEN 0x10000
-
-#define bSFactorQAM1 0xf /* Useless */
-#define bSFactorQAM2 0xf0
-#define bSFactorQAM3 0xf00
-#define bSFactorQAM4 0xf000
-#define bSFactorQAM5 0xf0000
-#define bSFactorQAM6 0xf0000
-#define bSFactorQAM7 0xf00000
-#define bSFactorQAM8 0xf000000
-#define bSFactorQAM9 0xf0000000
-#define bCSIScheme 0x100000
-
-#define bNoiseLvlTopSet 0x3 /* Useless */
-#define bChSmooth 0x4
-#define bChSmoothCfg1 0x38
-#define bChSmoothCfg2 0x1c0
-#define bChSmoothCfg3 0xe00
-#define bChSmoothCfg4 0x7000
-#define bMRCMode 0x800000
-#define bTHEVMCfg 0x7000000
-
-#define bLoopFitType 0x1 /* Useless */
-#define bUpdCFO 0x40
-#define bUpdCFOOffData 0x80
-#define bAdvUpdCFO 0x100
-#define bAdvTimeCtrl 0x800
-#define bUpdClko 0x1000
-#define bFC 0x6000
-#define bTrackingMode 0x8000
-#define bPhCmpEnable 0x10000
-#define bUpdClkoLTF 0x20000
-#define bComChCFO 0x40000
-#define bCSIEstiMode 0x80000
-#define bAdvUpdEqz 0x100000
-#define bUChCfg 0x7000000
-#define bUpdEqz 0x8000000
-
-/* Rx Pseduo noise */
-#define bRxPesudoNoiseOn 0x20000000 /* Useless */
-#define bRxPesudoNoise_A 0xff
-#define bRxPesudoNoise_B 0xff00
-#define bRxPesudoNoise_C 0xff0000
-#define bRxPesudoNoise_D 0xff000000
-#define bPesudoNoiseState_A 0xffff
-#define bPesudoNoiseState_B 0xffff0000
-#define bPesudoNoiseState_C 0xffff
-#define bPesudoNoiseState_D 0xffff0000
-
-/* 7. RF Register */
-/* Zebra1 */
-#define bZebra1_HSSIEnable 0x8 /* Useless */
-#define bZebra1_TRxControl 0xc00
-#define bZebra1_TRxGainSetting 0x07f
-#define bZebra1_RxCorner 0xc00
-#define bZebra1_TxChargePump 0x38
-#define bZebra1_RxChargePump 0x7
-#define bZebra1_ChannelNum 0xf80
-#define bZebra1_TxLPFBW 0x400
-#define bZebra1_RxLPFBW 0x600
-
-/* Zebra4 */
-#define bRTL8256RegModeCtrl1 0x100 /* Useless */
-#define bRTL8256RegModeCtrl0 0x40
-#define bRTL8256_TxLPFBW 0x18
-#define bRTL8256_RxLPFBW 0x600
-
-/* RTL8258 */
-#define bRTL8258_TxLPFBW 0xc /* Useless */
-#define bRTL8258_RxLPFBW 0xc00
-#define bRTL8258_RSSILPFBW 0xc0
-
-
/* */
/* Other Definition */
/* */
-/* byte endable for sb_write */
-#define bByte0 0x1 /* Useless */
-#define bByte1 0x2
-#define bByte2 0x4
-#define bByte3 0x8
-#define bWord0 0x3
-#define bWord1 0xc
-#define bDWord 0xf
-
/* for PutRegsetting & GetRegSetting BitMask */
#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */
#define bMaskByte1 0xff00
-#define bMaskByte2 0xff0000
#define bMaskByte3 0xff000000
-#define bMaskHWord 0xffff0000
-#define bMaskLWord 0x0000ffff
#define bMaskDWord 0xffffffff
#define bMask12Bits 0xfff
-#define bMaskH4Bits 0xf0000000
#define bMaskOFDM_D 0xffc00000
-#define bMaskCCK 0x3f3f3f3f
/* for PutRFRegsetting & GetRFRegSetting BitMask */
#define bRFRegOffsetMask 0xfffff
-#define bEnable 0x1 /* Useless */
-#define bDisable 0x0
-
-#define LeftAntenna 0x0 /* Useless */
-#define RightAntenna 0x1
-
-#define tCheckTxStatus 500 /* 500ms Useless */
-#define tUpdateRxCounter 100 /* 100ms */
-
-#define rateCCK 0 /* Useless */
-#define rateOFDM 1
-#define rateHT 2
-
-/* define Register-End */
-#define bPMAC_End 0x1ff /* Useless */
-#define bFPGAPHY0_End 0x8ff
-#define bFPGAPHY1_End 0x9ff
-#define bCCKPHY0_End 0xaff
-#define bOFDMPHY0_End 0xcff
-#define bOFDMPHY1_End 0xdff
-
-#define bPMACControl 0x0 /* Useless */
-#define bWMACControl 0x1
-#define bWNICControl 0x2
-
-#define PathA 0x0 /* Useless */
-#define PathB 0x1
-#define PathC 0x2
-#define PathD 0x3
-
-/*--------------------------Define Parameters-------------------------------*/
-
-
#endif
diff --git a/drivers/staging/rtl8188eu/include/hal_intf.h b/drivers/staging/rtl8188eu/include/hal_intf.h
index 8b65fcba1967..516a89647003 100644
--- a/drivers/staging/rtl8188eu/include/hal_intf.h
+++ b/drivers/staging/rtl8188eu/include/hal_intf.h
@@ -199,7 +199,7 @@ void rtw_hal_add_ra_tid(struct adapter *adapt, u32 bitmap, u8 arg, u8 level);
void rtw_hal_clone_data(struct adapter *dst_adapt,
struct adapter *src_adapt);
-void rtw_hal_bcn_related_reg_setting(struct adapter *padapter);
+void beacon_timing_control(struct adapter *padapter);
u32 rtw_hal_read_rfreg(struct adapter *padapter, enum rf_radio_path eRFPath,
u32 RegAddr, u32 BitMask);
diff --git a/drivers/staging/rtl8188eu/include/mlme_osdep.h b/drivers/staging/rtl8188eu/include/mlme_osdep.h
index eda16c06336a..8e919441c2aa 100644
--- a/drivers/staging/rtl8188eu/include/mlme_osdep.h
+++ b/drivers/staging/rtl8188eu/include/mlme_osdep.h
@@ -13,7 +13,6 @@
void rtw_init_mlme_timer(struct adapter *padapter);
void rtw_os_indicate_disconnect(struct adapter *adapter);
void rtw_os_indicate_connect(struct adapter *adapter);
-void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted);
void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie);
void rtw_reset_securitypriv(struct adapter *adapter);
diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h
index cfe5698fbbb1..c0114ad79788 100644
--- a/drivers/staging/rtl8188eu/include/osdep_service.h
+++ b/drivers/staging/rtl8188eu/include/osdep_service.h
@@ -80,8 +80,6 @@ void rtw_free_netdev(struct net_device *netdev);
#define FUNC_ADPT_FMT "%s(%s)"
#define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name
-u64 rtw_modular64(u64 x, u64 y);
-
/* Macros for handling unaligned memory accesses */
#define RTW_GET_BE24(a) ((((u32)(a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h
index 9abb7c320192..010f0c42368a 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h
@@ -333,7 +333,7 @@ void rtw_dynamic_check_timer_handlder(struct timer_list *t);
void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv);
-struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv);
+struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv);
int rtw_if_up(struct adapter *padapter);
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
index 327f7d1bc20c..d70780c8fd62 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -535,7 +535,6 @@ void report_del_sta_event(struct adapter *padapter,
void report_add_sta_event(struct adapter *padapter, unsigned char *addr,
int cam_idx);
-void beacon_timing_control(struct adapter *padapter);
u8 set_tx_beacon_cmd(struct adapter *padapter);
unsigned int setup_beacon_frame(struct adapter *padapter,
unsigned char *beacon_frame);
diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
index e660bd4d91ef..321b2c46479c 100644
--- a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
@@ -27,11 +27,6 @@ void rtw_os_indicate_connect(struct adapter *adapter)
netif_carrier_on(adapter->pnetdev);
}
-void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted)
-{
- indicate_wx_scan_complete_event(padapter);
-}
-
static struct rt_pmkid_list backup_pmkid[NUM_PMKID_CACHE];
void rtw_reset_securitypriv(struct adapter *adapter)
diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
index 105f3f21bdea..69d4b1d66b6f 100644
--- a/drivers/staging/rtl8188eu/os_dep/osdep_service.c
+++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
@@ -59,11 +59,6 @@ RETURN:
return;
}
-u64 rtw_modular64(u64 x, u64 y)
-{
- return do_div(x, y);
-}
-
void rtw_buf_free(u8 **buf, u32 *buf_len)
{
*buf_len = 0;
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
index eedf2cd831d1..aaab0d577453 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -122,8 +122,7 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
precvframe->pkt = pkt_copy;
skb_reserve(pkt_copy, 8 - ((size_t)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */
skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */
- memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len);
- skb_put(precvframe->pkt, skb_len);
+ skb_put_data(pkt_copy, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len);
} else {
DBG_88E("%s: alloc_skb fail , drop frag frame\n",
__func__);
diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig
index 11528d17bb3c..1007eea6c8fc 100644
--- a/drivers/staging/rtl8192e/Kconfig
+++ b/drivers/staging/rtl8192e/Kconfig
@@ -15,6 +15,7 @@ config RTLLIB_CRYPTO_CCMP
tristate "Support for rtllib CCMP crypto"
depends on RTLLIB
select CRYPTO_AES
+ select CRYPTO_CCM
default y
help
CCMP crypto driver for rtllib.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index 1b7e3fda7905..20e494186c9e 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -618,7 +618,7 @@ static void _rtl92e_dm_tx_update_tssi_strong_signal(struct net_device *dev,
static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- bool bHighpowerstate, viviflag = false;
+ bool viviflag = false;
struct dcmd_txcmd tx_cmd;
u8 powerlevelOFDM24G;
int i = 0, j = 0, k = 0;
@@ -632,7 +632,6 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev)
rtl92e_writeb(dev, Pw_Track_Flag, 0);
rtl92e_writeb(dev, FW_Busy_Flag, 0);
priv->rtllib->bdynamic_txpower_enable = false;
- bHighpowerstate = priv->bDynamicTxHighPower;
powerlevelOFDM24G = (u8)(priv->Pwr_Track>>24);
RF_Type = priv->rf_type;
@@ -1901,7 +1900,7 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
u8 cck_default_Rx = 0x2;
u8 cck_optional_Rx = 0x3;
long tmp_cck_max_pwdb = 0, tmp_cck_min_pwdb = 0, tmp_cck_sec_pwdb = 0;
- u8 cck_rx_ver2_max_index = 0, cck_rx_ver2_min_index = 0;
+ u8 cck_rx_ver2_max_index = 0;
u8 cck_rx_ver2_sec_index = 0;
u8 cur_rf_rssi;
long cur_cck_pwdb;
@@ -1984,7 +1983,6 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
if (rf_num == 1) {
cck_rx_ver2_max_index = i;
- cck_rx_ver2_min_index = i;
cck_rx_ver2_sec_index = i;
tmp_cck_max_pwdb = cur_cck_pwdb;
tmp_cck_min_pwdb = cur_cck_pwdb;
@@ -1997,7 +1995,6 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
tmp_cck_sec_pwdb = cur_cck_pwdb;
tmp_cck_min_pwdb = cur_cck_pwdb;
cck_rx_ver2_sec_index = i;
- cck_rx_ver2_min_index = i;
}
} else {
if (cur_cck_pwdb > tmp_cck_max_pwdb) {
@@ -2027,13 +2024,10 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
(cur_cck_pwdb > tmp_cck_min_pwdb)) {
;
} else if (cur_cck_pwdb == tmp_cck_min_pwdb) {
- if (tmp_cck_sec_pwdb == tmp_cck_min_pwdb) {
+ if (tmp_cck_sec_pwdb == tmp_cck_min_pwdb)
tmp_cck_min_pwdb = cur_cck_pwdb;
- cck_rx_ver2_min_index = i;
- }
} else if (cur_cck_pwdb < tmp_cck_min_pwdb) {
tmp_cck_min_pwdb = cur_cck_pwdb;
- cck_rx_ver2_min_index = i;
}
}
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index 2dd57e88276e..328f410daa03 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -479,7 +479,6 @@ enum wireless_mode {
#define P80211_OUI_LEN 3
struct rtllib_snap_hdr {
-
u8 dsap; /* always 0xAA */
u8 ssap; /* always 0xAA */
u8 ctrl; /* always 0x03 */
@@ -1940,7 +1939,7 @@ int rtllib_encrypt_fragment(
int hdr_len);
int rtllib_xmit(struct sk_buff *skb, struct net_device *dev);
-void rtllib_txb_free(struct rtllib_txb *);
+void rtllib_txb_free(struct rtllib_txb *txb);
/* rtllib_rx.c */
int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb,
@@ -2132,7 +2131,7 @@ static inline const char *escape_essid(const char *essid, u8 essid_len)
return escaped;
}
- snprintf(escaped, sizeof(escaped), "%*pEn", essid_len, essid);
+ snprintf(escaped, sizeof(escaped), "%*pE", essid_len, essid);
return escaped;
}
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
index 2581ed6d14fa..0cbf4a1a326b 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
@@ -17,6 +17,7 @@
#include "rtllib.h"
#include <linux/crypto.h>
+#include <crypto/aead.h>
#include <linux/scatterlist.h>
@@ -39,20 +40,13 @@ struct rtllib_ccmp_data {
int key_idx;
- struct crypto_tfm *tfm;
+ struct crypto_aead *tfm;
/* scratch buffers for virt_to_page() (crypto API) */
- u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
- tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
- u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
+ u8 tx_aad[2 * AES_BLOCK_LEN];
+ u8 rx_aad[2 * AES_BLOCK_LEN];
};
-static void rtllib_ccmp_aes_encrypt(struct crypto_tfm *tfm,
- const u8 pt[16], u8 ct[16])
-{
- crypto_cipher_encrypt_one((void *)tfm, ct, pt);
-}
-
static void *rtllib_ccmp_init(int key_idx)
{
struct rtllib_ccmp_data *priv;
@@ -62,7 +56,7 @@ static void *rtllib_ccmp_init(int key_idx)
goto fail;
priv->key_idx = key_idx;
- priv->tfm = (void *)crypto_alloc_cipher("aes", 0, 0);
+ priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tfm)) {
pr_debug("Could not allocate crypto API aes\n");
priv->tfm = NULL;
@@ -73,7 +67,7 @@ static void *rtllib_ccmp_init(int key_idx)
fail:
if (priv) {
if (priv->tfm)
- crypto_free_cipher((void *)priv->tfm);
+ crypto_free_aead(priv->tfm);
kfree(priv);
}
@@ -86,31 +80,18 @@ static void rtllib_ccmp_deinit(void *priv)
struct rtllib_ccmp_data *_priv = priv;
if (_priv && _priv->tfm)
- crypto_free_cipher((void *)_priv->tfm);
+ crypto_free_aead(_priv->tfm);
kfree(priv);
}
-static inline void xor_block(u8 *b, u8 *a, size_t len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- b[i] ^= a[i];
-}
-
-
-
-static void ccmp_init_blocks(struct crypto_tfm *tfm,
- struct rtllib_hdr_4addr *hdr,
- u8 *pn, size_t dlen, u8 *b0, u8 *auth,
- u8 *s0)
+static int ccmp_init_iv_and_aad(struct rtllib_hdr_4addr *hdr,
+ u8 *pn, u8 *iv, u8 *aad)
{
u8 *pos, qc = 0;
size_t aad_len;
u16 fc;
int a4_included, qc_included;
- u8 aad[2 * AES_BLOCK_LEN];
fc = le16_to_cpu(hdr->frame_ctl);
a4_included = ((fc & (RTLLIB_FCTL_TODS | RTLLIB_FCTL_FROMDS)) ==
@@ -128,18 +109,19 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
qc = *pos & 0x0f;
aad_len += 2;
}
- /* CCM Initial Block:
- * Flag (Include authentication header, M=3 (8-octet MIC),
- * L=1 (2-octet Dlen))
- * Nonce: 0x00 | A2 | PN
- * Dlen
+ /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
+ * mode authentication are not allowed to collide, yet both are derived
+ * from the same vector. We only set L := 1 here to indicate that the
+ * data size can be represented in (L+1) bytes. The CCM layer will take
+ * care of storing the data length in the top (L+1) bytes and setting
+ * and clearing the other bits as is required to derive the two IVs.
*/
- b0[0] = 0x59;
- b0[1] = qc;
- memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
- memcpy(b0 + 8, pn, CCMP_PN_LEN);
- b0[14] = (dlen >> 8) & 0xff;
- b0[15] = dlen & 0xff;
+ iv[0] = 0x1;
+
+ /* Nonce: QC | A2 | PN */
+ iv[1] = qc;
+ memcpy(iv + 2, hdr->addr2, ETH_ALEN);
+ memcpy(iv + 8, pn, CCMP_PN_LEN);
/* AAD:
* FC with bits 4..6 and 11..13 masked to zero; 14 is always one
@@ -149,31 +131,21 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
* QC (if present)
*/
pos = (u8 *) hdr;
- aad[0] = 0; /* aad_len >> 8 */
- aad[1] = aad_len & 0xff;
- aad[2] = pos[0] & 0x8f;
- aad[3] = pos[1] & 0xc7;
- memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
+ aad[0] = pos[0] & 0x8f;
+ aad[1] = pos[1] & 0xc7;
+ memcpy(aad + 2, hdr->addr1, 3 * ETH_ALEN);
pos = (u8 *) &hdr->seq_ctl;
- aad[22] = pos[0] & 0x0f;
- aad[23] = 0; /* all bits masked */
- memset(aad + 24, 0, 8);
+ aad[20] = pos[0] & 0x0f;
+ aad[21] = 0; /* all bits masked */
+ memset(aad + 22, 0, 8);
if (a4_included)
- memcpy(aad + 24, hdr->addr4, ETH_ALEN);
+ memcpy(aad + 22, hdr->addr4, ETH_ALEN);
if (qc_included) {
- aad[a4_included ? 30 : 24] = qc;
+ aad[a4_included ? 28 : 22] = qc;
/* rest of QC masked */
}
- /* Start with the first block and AAD */
- rtllib_ccmp_aes_encrypt(tfm, b0, auth);
- xor_block(auth, aad, AES_BLOCK_LEN);
- rtllib_ccmp_aes_encrypt(tfm, auth, auth);
- xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
- rtllib_ccmp_aes_encrypt(tfm, auth, auth);
- b0[0] &= 0x07;
- b0[14] = b0[15] = 0;
- rtllib_ccmp_aes_encrypt(tfm, b0, s0);
+ return aad_len;
}
@@ -181,7 +153,7 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
static int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct rtllib_ccmp_data *key = priv;
- int data_len, i;
+ int i;
u8 *pos;
struct rtllib_hdr_4addr *hdr;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
@@ -191,7 +163,6 @@ static int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
skb->len < hdr_len)
return -1;
- data_len = skb->len - hdr_len;
pos = skb_push(skb, CCMP_HDR_LEN);
memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
pos += hdr_len;
@@ -213,40 +184,37 @@ static int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
*pos++ = key->tx_pn[1];
*pos++ = key->tx_pn[0];
-
hdr = (struct rtllib_hdr_4addr *) skb->data;
if (!tcb_desc->bHwSec) {
- int blocks, last, len;
- u8 *mic;
- u8 *b0 = key->tx_b0;
- u8 *b = key->tx_b;
- u8 *e = key->tx_e;
- u8 *s0 = key->tx_s0;
-
- mic = skb_put(skb, CCMP_MIC_LEN);
-
- ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len,
- b0, b, s0);
-
- blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
- last = data_len % AES_BLOCK_LEN;
-
- for (i = 1; i <= blocks; i++) {
- len = (i == blocks && last) ? last : AES_BLOCK_LEN;
- /* Authentication */
- xor_block(b, pos, len);
- rtllib_ccmp_aes_encrypt(key->tfm, b, b);
- /* Encryption, with counter */
- b0[14] = (i >> 8) & 0xff;
- b0[15] = i & 0xff;
- rtllib_ccmp_aes_encrypt(key->tfm, b0, e);
- xor_block(pos, e, len);
- pos += len;
- }
+ struct aead_request *req;
+ struct scatterlist sg[2];
+ u8 *aad = key->tx_aad;
+ u8 iv[AES_BLOCK_LEN];
+ int aad_len, ret;
+ int data_len = skb->len - hdr_len - CCMP_HDR_LEN;
+
+ req = aead_request_alloc(key->tfm, GFP_ATOMIC);
+ if (!req)
+ return -ENOMEM;
+
+ aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad);
+
+ skb_put(skb, CCMP_MIC_LEN);
+ sg_init_table(sg, 2);
+ sg_set_buf(&sg[0], aad, aad_len);
+ sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN,
+ data_len + CCMP_MIC_LEN);
- for (i = 0; i < CCMP_MIC_LEN; i++)
- mic[i] = b[i] ^ s0[i];
+ aead_request_set_callback(req, 0, NULL, NULL);
+ aead_request_set_ad(req, aad_len);
+ aead_request_set_crypt(req, sg, sg, data_len, iv);
+
+ ret = crypto_aead_encrypt(req);
+ aead_request_free(req);
+
+ return ret;
}
+
return 0;
}
@@ -302,35 +270,31 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
return -4;
}
if (!tcb_desc->bHwSec) {
- size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN -
- CCMP_MIC_LEN;
- u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
- u8 *b0 = key->rx_b0;
- u8 *b = key->rx_b;
- u8 *a = key->rx_a;
- int i, blocks, last, len;
-
-
- ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
- xor_block(mic, b, CCMP_MIC_LEN);
-
- blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
- last = data_len % AES_BLOCK_LEN;
-
- for (i = 1; i <= blocks; i++) {
- len = (i == blocks && last) ? last : AES_BLOCK_LEN;
- /* Decrypt, with counter */
- b0[14] = (i >> 8) & 0xff;
- b0[15] = i & 0xff;
- rtllib_ccmp_aes_encrypt(key->tfm, b0, b);
- xor_block(pos, b, len);
- /* Authentication */
- xor_block(a, pos, len);
- rtllib_ccmp_aes_encrypt(key->tfm, a, a);
- pos += len;
- }
+ size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN;
+ struct aead_request *req;
+ struct scatterlist sg[2];
+ u8 *aad = key->rx_aad;
+ u8 iv[AES_BLOCK_LEN];
+ int aad_len, ret;
+
+ req = aead_request_alloc(key->tfm, GFP_ATOMIC);
+ if(!req)
+ return -ENOMEM;
+
+ aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad);
+
+ sg_init_table(sg, 2);
+ sg_set_buf(&sg[0], aad, aad_len);
+ sg_set_buf(&sg[1], pos, data_len);
+
+ aead_request_set_callback(req, 0, NULL, NULL);
+ aead_request_set_ad(req, aad_len);
+ aead_request_set_crypt(req, sg, sg, data_len, iv);
+
+ ret = crypto_aead_decrypt(req);
+ aead_request_free(req);
- if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
+ if (ret) {
if (net_ratelimit()) {
pr_debug("CCMP: decrypt failed: STA= %pM\n",
hdr->addr2);
@@ -354,7 +318,7 @@ static int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
{
struct rtllib_ccmp_data *data = priv;
int keyidx;
- struct crypto_tfm *tfm = data->tfm;
+ struct crypto_aead *tfm = data->tfm;
keyidx = data->key_idx;
memset(data, 0, sizeof(*data));
@@ -371,7 +335,9 @@ static int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
data->rx_pn[4] = seq[1];
data->rx_pn[5] = seq[0];
}
- crypto_cipher_setkey((void *)data->tfm, data->key, CCMP_TK_LEN);
+ if (crypto_aead_setauthsize(data->tfm, CCMP_MIC_LEN) ||
+ crypto_aead_setkey(data->tfm, data->key, CCMP_TK_LEN))
+ return -1;
} else if (len == 0) {
data->key_set = 0;
} else {
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index 0c19ac2bc3bf..0bae0a0a4cbe 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -1300,7 +1300,6 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
struct rx_ts_record *pTS = NULL;
u16 fc, sc, SeqNum = 0;
u8 type, stype, multicast = 0, unicast = 0, nr_subframes = 0, TID = 0;
- u8 *payload;
u8 dst[ETH_ALEN];
u8 src[ETH_ALEN];
u8 bssid[ETH_ALEN] = {0};
@@ -1412,7 +1411,6 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
/* Parse rx data frame (For AMSDU) */
/* skb: hdr + (possible reassembled) full plaintext payload */
- payload = skb->data + hdrlen;
rxb = kmalloc(sizeof(struct rtllib_rxb), GFP_ATOMIC);
if (!rxb)
goto rx_dropped;
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index e29e8d6f4611..f2f7529e7c80 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -1382,15 +1382,10 @@ rtllib_association_req(struct rtllib_network *beacon,
ieee->assocreq_ies = NULL;
ies = &(hdr->info_element[0].id);
ieee->assocreq_ies_len = (skb->data + skb->len) - ies;
- ieee->assocreq_ies = kmalloc(ieee->assocreq_ies_len, GFP_ATOMIC);
- if (ieee->assocreq_ies)
- memcpy(ieee->assocreq_ies, ies, ieee->assocreq_ies_len);
- else {
- netdev_info(ieee->dev,
- "%s()Warning: can't alloc memory for assocreq_ies\n",
- __func__);
+ ieee->assocreq_ies = kmemdup(ies, ieee->assocreq_ies_len, GFP_ATOMIC);
+ if (!ieee->assocreq_ies)
ieee->assocreq_ies_len = 0;
- }
+
return skb;
}
@@ -2259,17 +2254,12 @@ rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb,
ieee->assocresp_ies = NULL;
ies = &(assoc_resp->info_element[0].id);
ieee->assocresp_ies_len = (skb->data + skb->len) - ies;
- ieee->assocresp_ies = kmalloc(ieee->assocresp_ies_len,
+ ieee->assocresp_ies = kmemdup(ies,
+ ieee->assocresp_ies_len,
GFP_ATOMIC);
- if (ieee->assocresp_ies)
- memcpy(ieee->assocresp_ies, ies,
- ieee->assocresp_ies_len);
- else {
- netdev_info(ieee->dev,
- "%s()Warning: can't alloc memory for assocresp_ies\n",
- __func__);
+ if (!ieee->assocresp_ies)
ieee->assocresp_ies_len = 0;
- }
+
rtllib_associate_complete(ieee);
} else {
/* aid could not been allocated */
diff --git a/drivers/staging/rtl8192u/Kconfig b/drivers/staging/rtl8192u/Kconfig
index 22c2165e8b1c..1edca5c304fb 100644
--- a/drivers/staging/rtl8192u/Kconfig
+++ b/drivers/staging/rtl8192u/Kconfig
@@ -6,3 +6,5 @@ config RTL8192U
select WIRELESS_EXT
select WEXT_PRIV
select CRYPTO
+ select CRYPTO_AES
+ select CRYPTO_CCM
diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.c b/drivers/staging/rtl8192u/ieee80211/dot11d.c
index 130ddfe9868f..bc642076b96f 100644
--- a/drivers/staging/rtl8192u/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8192u/ieee80211/dot11d.c
@@ -12,7 +12,7 @@ void rtl8192u_dot11d_init(struct ieee80211_device *ieee)
dot11d_info->state = DOT11D_STATE_NONE;
dot11d_info->country_ie_len = 0;
memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
- memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
+ memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
RESET_CIE_WATCHDOG(ieee);
netdev_info(ieee->dev, "rtl8192u_dot11d_init()\n");
@@ -25,8 +25,8 @@ void dot11d_reset(struct ieee80211_device *ieee)
u32 i;
struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
/* Clear old channel map */
- memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER+1);
- memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
+ memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
+ memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
/* Set new channel map */
for (i = 1; i <= 11; i++)
(dot11d_info->channel_map)[i] = 1;
@@ -56,8 +56,8 @@ void dot11d_update_country_ie(struct ieee80211_device *dev, u8 *pTaddr,
u8 i, j, NumTriples, MaxChnlNum;
struct chnl_txpower_triple *pTriple;
- memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER+1);
- memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
+ memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
+ memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
MaxChnlNum = 0;
NumTriples = (CoutryIeLen - 3) / 3; /* skip 3-byte country string. */
pTriple = (struct chnl_txpower_triple *)(pCoutryIe + 3);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index d36963469015..9576b647f6b1 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -169,9 +169,9 @@ struct cb_desc {
#define MGN_MCS14 0x8e
#define MGN_MCS15 0x8f
-#define aSifsTime ((priv->ieee80211->current_network.mode == IEEE_A || \
+#define aSifsTime ((priv->ieee80211->current_network.mode == IEEE_A || \
priv->ieee80211->current_network.mode == IEEE_N_24G || \
- priv->ieee80211->current_network.mode == IEEE_N_5G) ? \
+ priv->ieee80211->current_network.mode == IEEE_N_5G) ? \
16 : 10)
#define MGMT_QUEUE_NUM 5
@@ -387,7 +387,7 @@ struct ieee_param {
#define IEEE80211_STYPE_ACK 0x00D0
#define IEEE80211_STYPE_CFEND 0x00E0
#define IEEE80211_STYPE_CFENDACK 0x00F0
-#define IEEE80211_STYPE_BLOCKACK 0x0094
+#define IEEE80211_STYPE_BLOCKACK 0x0094
/* data */
#define IEEE80211_STYPE_DATA 0x0000
@@ -452,23 +452,23 @@ do { if (ieee80211_debug_level & (level)) \
printk(KERN_DEBUG "ieee80211: " fmt, ## args); } while (0)
//wb added to debug out data buf
//if you want print DATA buffer related BA, please set ieee80211_debug_level to DATA|BA
-#define IEEE80211_DEBUG_DATA(level, data, datalen) \
- do { if ((ieee80211_debug_level & (level)) == (level)) \
- { \
- int i; \
- u8 *pdata = (u8 *) data; \
- printk(KERN_DEBUG "ieee80211: %s()\n", __func__); \
- for (i = 0; i < (int)(datalen); i++) \
- { \
- printk("%2x ", pdata[i]); \
- if ((i + 1) % 16 == 0) printk("\n"); \
- } \
- printk("\n"); \
- } \
+#define IEEE80211_DEBUG_DATA(level, data, datalen) \
+ do { if ((ieee80211_debug_level & (level)) == (level)) \
+ { \
+ int i; \
+ u8 *pdata = (u8 *)data; \
+ printk(KERN_DEBUG "ieee80211: %s()\n", __func__); \
+ for (i = 0; i < (int)(datalen); i++) { \
+ printk("%2x ", pdata[i]); \
+ if ((i + 1) % 16 == 0) \
+ printk("\n"); \
+ } \
+ printk("\n"); \
+ } \
} while (0)
#else
#define IEEE80211_DEBUG (level, fmt, args...) do {} while (0)
-#define IEEE80211_DEBUG_DATA (level, data, datalen) do {} while(0)
+#define IEEE80211_DEBUG_DATA (level, data, datalen) do {} while (0)
#endif /* CONFIG_IEEE80211_DEBUG */
/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
@@ -1649,10 +1649,8 @@ struct ieee80211_device {
struct list_head Rx_TS_Pending_List;
struct list_head Rx_TS_Unused_List;
struct rx_ts_record RxTsRecord[TOTAL_TS_NUM];
-//#ifdef TO_DO_LIST
struct rx_reorder_entry RxReorderEntry[128];
struct list_head RxReorder_Unused_List;
-//#endif
// Qos related. Added by Annie, 2005-11-01.
// PSTA_QOS pStaQos;
u8 ForcedPriority; // Force per-packet priority 1~7. (default: 0, not to force it.)
@@ -2015,8 +2013,8 @@ struct ieee80211_device {
#define IEEE_A (1<<0)
#define IEEE_B (1<<1)
#define IEEE_G (1<<2)
-#define IEEE_N_24G (1<<4)
-#define IEEE_N_5G (1<<5)
+#define IEEE_N_24G (1<<4)
+#define IEEE_N_5G (1<<5)
#define IEEE_MODE_MASK (IEEE_A | IEEE_B | IEEE_G)
/* Generate a 802.11 header */
@@ -2426,7 +2424,7 @@ static inline const char *escape_essid(const char *essid, u8 essid_len)
return escaped;
}
- snprintf(escaped, sizeof(escaped), "%*pEn", essid_len, essid);
+ snprintf(escaped, sizeof(escaped), "%*pE", essid_len, essid);
return escaped;
}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt.c
index 36987fccac5d..01012dddcd73 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt.c
@@ -176,7 +176,7 @@ struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
}
-static void *ieee80211_crypt_null_init(int keyidx) { return (void *) 1; }
+static void *ieee80211_crypt_null_init(int keyidx) { return (void *)1; }
static void ieee80211_crypt_null_deinit(void *priv) {}
static struct ieee80211_crypto_ops ieee80211_crypt_null = {
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
index d7188b3f3190..c241cf484023 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
@@ -19,6 +19,7 @@
#include "ieee80211.h"
#include <linux/crypto.h>
+#include <crypto/aead.h>
#include <linux/scatterlist.h>
MODULE_AUTHOR("Jouni Malinen");
@@ -44,20 +45,13 @@ struct ieee80211_ccmp_data {
int key_idx;
- struct crypto_tfm *tfm;
+ struct crypto_aead *tfm;
/* scratch buffers for virt_to_page() (crypto API) */
- u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
- tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
- u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
+ u8 tx_aad[2 * AES_BLOCK_LEN];
+ u8 rx_aad[2 * AES_BLOCK_LEN];
};
-static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
- const u8 pt[16], u8 ct[16])
-{
- crypto_cipher_encrypt_one((void *)tfm, ct, pt);
-}
-
static void *ieee80211_ccmp_init(int key_idx)
{
struct ieee80211_ccmp_data *priv;
@@ -67,7 +61,7 @@ static void *ieee80211_ccmp_init(int key_idx)
goto fail;
priv->key_idx = key_idx;
- priv->tfm = (void *)crypto_alloc_cipher("aes", 0, 0);
+ priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tfm)) {
pr_debug("ieee80211_crypt_ccmp: could not allocate crypto API aes\n");
priv->tfm = NULL;
@@ -79,7 +73,7 @@ static void *ieee80211_ccmp_init(int key_idx)
fail:
if (priv) {
if (priv->tfm)
- crypto_free_cipher((void *)priv->tfm);
+ crypto_free_aead(priv->tfm);
kfree(priv);
}
@@ -91,28 +85,17 @@ static void ieee80211_ccmp_deinit(void *priv)
struct ieee80211_ccmp_data *_priv = priv;
if (_priv && _priv->tfm)
- crypto_free_cipher((void *)_priv->tfm);
+ crypto_free_aead(_priv->tfm);
kfree(priv);
}
-static inline void xor_block(u8 *b, u8 *a, size_t len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- b[i] ^= a[i];
-}
-
-static void ccmp_init_blocks(struct crypto_tfm *tfm,
- struct rtl_80211_hdr_4addr *hdr,
- u8 *pn, size_t dlen, u8 *b0, u8 *auth,
- u8 *s0)
+static int ccmp_init_iv_and_aad(struct rtl_80211_hdr_4addr *hdr,
+ u8 *pn, u8 *iv, u8 *aad)
{
u8 *pos, qc = 0;
size_t aad_len;
u16 fc;
int a4_included, qc_included;
- u8 aad[2 * AES_BLOCK_LEN];
fc = le16_to_cpu(hdr->frame_ctl);
a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
@@ -133,18 +116,20 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
qc = *pos & 0x0f;
aad_len += 2;
}
- /* CCM Initial Block:
- * Flag (Include authentication header, M=3 (8-octet MIC),
- * L=1 (2-octet Dlen))
- * Nonce: 0x00 | A2 | PN
- * Dlen
+
+ /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
+ * mode authentication are not allowed to collide, yet both are derived
+ * from the same vector. We only set L := 1 here to indicate that the
+ * data size can be represented in (L+1) bytes. The CCM layer will take
+ * care of storing the data length in the top (L+1) bytes and setting
+ * and clearing the other bits as is required to derive the two IVs.
*/
- b0[0] = 0x59;
- b0[1] = qc;
- memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
- memcpy(b0 + 8, pn, CCMP_PN_LEN);
- b0[14] = (dlen >> 8) & 0xff;
- b0[15] = dlen & 0xff;
+ iv[0] = 0x1;
+
+ /* Nonce: QC | A2 | PN */
+ iv[1] = qc;
+ memcpy(iv + 2, hdr->addr2, ETH_ALEN);
+ memcpy(iv + 8, pn, CCMP_PN_LEN);
/* AAD:
* FC with bits 4..6 and 11..13 masked to zero; 14 is always one
@@ -154,38 +139,27 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
* QC (if present)
*/
pos = (u8 *)hdr;
- aad[0] = 0; /* aad_len >> 8 */
- aad[1] = aad_len & 0xff;
- aad[2] = pos[0] & 0x8f;
- aad[3] = pos[1] & 0xc7;
- memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
+ aad[0] = pos[0] & 0x8f;
+ aad[1] = pos[1] & 0xc7;
+ memcpy(aad + 2, hdr->addr1, 3 * ETH_ALEN);
pos = (u8 *)&hdr->seq_ctl;
- aad[22] = pos[0] & 0x0f;
- aad[23] = 0; /* all bits masked */
- memset(aad + 24, 0, 8);
+ aad[20] = pos[0] & 0x0f;
+ aad[21] = 0; /* all bits masked */
+ memset(aad + 22, 0, 8);
if (a4_included)
- memcpy(aad + 24, hdr->addr4, ETH_ALEN);
+ memcpy(aad + 22, hdr->addr4, ETH_ALEN);
if (qc_included) {
- aad[a4_included ? 30 : 24] = qc;
+ aad[a4_included ? 28 : 22] = qc;
/* rest of QC masked */
}
- /* Start with the first block and AAD */
- ieee80211_ccmp_aes_encrypt(tfm, b0, auth);
- xor_block(auth, aad, AES_BLOCK_LEN);
- ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
- xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
- ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
- b0[0] &= 0x07;
- b0[14] = 0;
- b0[15] = 0;
- ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
+ return aad_len;
}
static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct ieee80211_ccmp_data *key = priv;
- int data_len, i;
+ int i;
u8 *pos;
struct rtl_80211_hdr_4addr *hdr;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
@@ -195,7 +169,6 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
skb->len < hdr_len)
return -1;
- data_len = skb->len - hdr_len;
pos = skb_push(skb, CCMP_HDR_LEN);
memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
pos += hdr_len;
@@ -220,36 +193,34 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
hdr = (struct rtl_80211_hdr_4addr *)skb->data;
if (!tcb_desc->bHwSec) {
- int blocks, last, len;
- u8 *mic;
- u8 *b0 = key->tx_b0;
- u8 *b = key->tx_b;
- u8 *e = key->tx_e;
- u8 *s0 = key->tx_s0;
-
- /* mic is moved to here by john */
- mic = skb_put(skb, CCMP_MIC_LEN);
-
- ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
-
- blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
- last = data_len % AES_BLOCK_LEN;
-
- for (i = 1; i <= blocks; i++) {
- len = (i == blocks && last) ? last : AES_BLOCK_LEN;
- /* Authentication */
- xor_block(b, pos, len);
- ieee80211_ccmp_aes_encrypt(key->tfm, b, b);
- /* Encryption, with counter */
- b0[14] = (i >> 8) & 0xff;
- b0[15] = i & 0xff;
- ieee80211_ccmp_aes_encrypt(key->tfm, b0, e);
- xor_block(pos, e, len);
- pos += len;
- }
+ struct aead_request *req;
+ struct scatterlist sg[2];
+ u8 *aad = key->tx_aad;
+ u8 iv[AES_BLOCK_LEN];
+ int aad_len, ret;
+ size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN;
- for (i = 0; i < CCMP_MIC_LEN; i++)
- mic[i] = b[i] ^ s0[i];
+ req = aead_request_alloc(key->tfm, GFP_ATOMIC);
+ if (!req)
+ return -ENOMEM;
+
+ aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad);
+
+ skb_put(skb, CCMP_MIC_LEN);
+
+ sg_init_table(sg, 2);
+ sg_set_buf(&sg[0], aad, aad_len);
+ sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN,
+ data_len + CCMP_MIC_LEN);
+
+ aead_request_set_callback(req, 0, NULL, NULL);
+ aead_request_set_ad(req, aad_len);
+ aead_request_set_crypt(req, sg, sg, data_len, iv);
+
+ ret = crypto_aead_encrypt(req);
+ aead_request_free(req);
+
+ return ret;
}
return 0;
}
@@ -309,33 +280,31 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
return -4;
}
if (!tcb_desc->bHwSec) {
- size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN;
- u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
- u8 *b0 = key->rx_b0;
- u8 *b = key->rx_b;
- u8 *a = key->rx_a;
- int i, blocks, last, len;
-
- ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
- xor_block(mic, b, CCMP_MIC_LEN);
-
- blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
- last = data_len % AES_BLOCK_LEN;
-
- for (i = 1; i <= blocks; i++) {
- len = (i == blocks && last) ? last : AES_BLOCK_LEN;
- /* Decrypt, with counter */
- b0[14] = (i >> 8) & 0xff;
- b0[15] = i & 0xff;
- ieee80211_ccmp_aes_encrypt(key->tfm, b0, b);
- xor_block(pos, b, len);
- /* Authentication */
- xor_block(a, pos, len);
- ieee80211_ccmp_aes_encrypt(key->tfm, a, a);
- pos += len;
- }
+ struct aead_request *req;
+ struct scatterlist sg[2];
+ u8 *aad = key->rx_aad;
+ u8 iv[AES_BLOCK_LEN];
+ int aad_len, ret;
+ size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN;
+
+ req = aead_request_alloc(key->tfm, GFP_ATOMIC);
+ if (!req)
+ return -ENOMEM;
+
+ aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad);
+
+ sg_init_table(sg, 2);
+ sg_set_buf(&sg[0], aad, aad_len);
+ sg_set_buf(&sg[1], pos, data_len);
+
+ aead_request_set_callback(req, 0, NULL, NULL);
+ aead_request_set_ad(req, aad_len);
+ aead_request_set_crypt(req, sg, sg, data_len, iv);
+
+ ret = crypto_aead_decrypt(req);
+ aead_request_free(req);
- if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
+ if (ret) {
if (net_ratelimit()) {
netdev_dbg(skb->dev, "CCMP: decrypt failed: STA=%pM\n",
hdr->addr2);
@@ -358,12 +327,11 @@ static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
{
struct ieee80211_ccmp_data *data = priv;
int keyidx;
- struct crypto_tfm *tfm = data->tfm;
+ struct crypto_aead *tfm = data->tfm;
keyidx = data->key_idx;
memset(data, 0, sizeof(*data));
data->key_idx = keyidx;
- data->tfm = tfm;
if (len == CCMP_TK_LEN) {
memcpy(data->key, key, CCMP_TK_LEN);
data->key_set = 1;
@@ -375,7 +343,9 @@ static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
data->rx_pn[4] = seq[1];
data->rx_pn[5] = seq[0];
}
- crypto_cipher_setkey((void *)data->tfm, data->key, CCMP_TK_LEN);
+ if (crypto_aead_setauthsize(tfm, CCMP_MIC_LEN) ||
+ crypto_aead_setkey(tfm, data->key, CCMP_TK_LEN))
+ return -1;
} else if (len == 0) {
data->key_set = 0;
} else {
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
index 0927b2b15151..6f4710171151 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
@@ -160,7 +160,7 @@ static inline u16 Hi16(u32 val)
static inline u16 Mk16(u8 hi, u8 lo)
{
- return lo | (((u16) hi) << 8);
+ return lo | (((u16)hi) << 8);
}
static const u16 Sbox[256] = {
@@ -238,7 +238,7 @@ static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
* Make temporary area overlap WEP seed so that the final copy can be
* avoided on little endian hosts.
*/
- u16 *PPK = (u16 *) &WEPSeed[4];
+ u16 *PPK = (u16 *)&WEPSeed[4];
/* Step 1 - make copy of TTAK and bring in TSC */
PPK[0] = TTAK[0];
@@ -299,7 +299,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
skb->len < hdr_len)
return -1;
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
if (!tcb_desc->bHwSec) {
if (!tkey->tx_phase1_done) {
@@ -343,7 +343,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
icv[2] = crc >> 16;
icv[3] = crc >> 24;
crypto_sync_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
- sg_init_one(&sg, pos, len+4);
+ sg_init_one(&sg, pos, len + 4);
skcipher_request_set_sync_tfm(req, tkey->tx_tfm_arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
@@ -383,7 +383,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (skb->len < hdr_len + 8 + 4)
return -1;
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
pos = skb->data + hdr_len;
keyidx = pos[3];
if (!(keyidx & BIT(5))) {
@@ -435,7 +435,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
plen = skb->len - hdr_len - 12;
crypto_sync_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
- sg_init_one(&sg, pos, plen+4);
+ sg_init_one(&sg, pos, plen + 4);
skcipher_request_set_sync_tfm(req, tkey->rx_tfm_arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
@@ -523,7 +523,7 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr)
{
struct rtl_80211_hdr_4addr *hdr11;
- hdr11 = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr11 = (struct rtl_80211_hdr_4addr *)skb->data;
switch (le16_to_cpu(hdr11->frame_ctl) &
(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
case IEEE80211_FCTL_TODS:
@@ -556,7 +556,7 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *pri
u8 *pos;
struct rtl_80211_hdr_4addr *hdr;
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
printk(KERN_DEBUG "Invalid packet for Michael MIC add "
@@ -599,7 +599,7 @@ static void ieee80211_michael_mic_failure(struct net_device *dev,
memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = sizeof(ev);
- wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev);
+ wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
}
static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
@@ -609,7 +609,7 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
u8 mic[8];
struct rtl_80211_hdr_4addr *hdr;
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
if (!tkey->key_set)
return -1;
@@ -626,7 +626,7 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
return -1;
if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
struct rtl_80211_hdr_4addr *hdr;
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
printk(KERN_DEBUG "%s: Michael MIC verification failed for "
"MSDU from %pM keyidx=%d\n",
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
index 805493a0870d..26482c3dcd1c 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
@@ -135,7 +135,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
icv[3] = crc >> 24;
crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen);
- sg_init_one(&sg, pos, len+4);
+ sg_init_one(&sg, pos, len + 4);
skcipher_request_set_sync_tfm(req, wep->tx_tfm);
skcipher_request_set_callback(req, 0, NULL, NULL);
@@ -192,7 +192,7 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen);
- sg_init_one(&sg, pos, plen+4);
+ sg_init_one(&sg, pos, plen + 4);
skcipher_request_set_sync_tfm(req, wep->rx_tfm);
skcipher_request_set_callback(req, 0, NULL, NULL);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index 0a3e478fccd6..5c33bcb0db2e 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -103,17 +103,17 @@ ieee80211_frag_cache_get(struct ieee80211_device *ieee,
u8 tid;
if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
- hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)hdr;
- tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
+ hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)hdr;
+ tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
+ tid = UP2AC(tid);
+ tid++;
} else if (IEEE80211_QOS_HAS_SEQ(fc)) {
- hdr_3addrqos = (struct rtl_80211_hdr_3addrqos *)hdr;
- tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
+ hdr_3addrqos = (struct rtl_80211_hdr_3addrqos *)hdr;
+ tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID;
+ tid = UP2AC(tid);
+ tid++;
} else {
- tid = 0;
+ tid = 0;
}
if (frag == 0) {
@@ -124,7 +124,7 @@ ieee80211_frag_cache_get(struct ieee80211_device *ieee,
2 /* alignment */ +
8 /* WEP */ +
ETH_ALEN /* WDS */ +
- (IEEE80211_QOS_HAS_SEQ(fc)?2:0) /* QOS Control */);
+ (IEEE80211_QOS_HAS_SEQ(fc) ? 2 : 0) /* QOS Control */);
if (!skb)
return NULL;
@@ -145,7 +145,7 @@ ieee80211_frag_cache_get(struct ieee80211_device *ieee,
} else {
/* received a fragment of a frame for which the head fragment
* should have already been received */
- entry = ieee80211_frag_cache_find(ieee, seq, frag, tid,hdr->addr2,
+ entry = ieee80211_frag_cache_find(ieee, seq, frag, tid, hdr->addr2,
hdr->addr1);
if (entry) {
entry->last_frag = frag;
@@ -169,18 +169,18 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
struct rtl_80211_hdr_4addrqos *hdr_4addrqos;
u8 tid;
- if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
- hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)hdr;
- tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
+ if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
+ hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)hdr;
+ tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
+ tid = UP2AC(tid);
+ tid++;
} else if (IEEE80211_QOS_HAS_SEQ(fc)) {
- hdr_3addrqos = (struct rtl_80211_hdr_3addrqos *)hdr;
- tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
+ hdr_3addrqos = (struct rtl_80211_hdr_3addrqos *)hdr;
+ tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID;
+ tid = UP2AC(tid);
+ tid++;
} else {
- tid = 0;
+ tid = 0;
}
entry = ieee80211_frag_cache_find(ieee, seq, -1, tid, hdr->addr2,
@@ -216,10 +216,10 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
struct rtl_80211_hdr_3addr *hdr = (struct rtl_80211_hdr_3addr *)skb->data;
rx_stats->len = skb->len;
- ieee80211_rx_mgt(ieee,(struct rtl_80211_hdr_4addr *)skb->data,rx_stats);
+ ieee80211_rx_mgt(ieee, (struct rtl_80211_hdr_4addr *)skb->data, rx_stats);
/* if ((ieee->state == IEEE80211_LINKED) && (memcmp(hdr->addr3, ieee->current_network.bssid, ETH_ALEN))) */
- if ((memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN)))/* use ADDR1 to perform address matching for Management frames */
- {
+ if ((memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN))) {
+ /* use ADDR1 to perform address matching for Management frames */
dev_kfree_skb_any(skb);
return 0;
}
@@ -281,11 +281,11 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char rfc1042_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+static unsigned char rfc1042_header[] = {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char bridge_tunnel_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+static unsigned char bridge_tunnel_header[] = {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
/* No encapsulation header if EtherType < 0x600 (=length) */
/* Called by ieee80211_rx_frame_decrypt */
@@ -300,7 +300,7 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
if (skb->len < 24)
return 0;
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
/* check that the frame is unicast frame to us */
@@ -339,12 +339,11 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
if (!crypt || !crypt->ops->decrypt_mpdu)
return 0;
- if (ieee->hwsec_active)
- {
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb+ MAX_DEV_ADDR_SIZE);
+ if (ieee->hwsec_active) {
+ struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->bHwSec = 1;
}
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
if (ieee->tkip_countermeasures &&
@@ -386,13 +385,12 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, struct sk_buff *s
if (!crypt || !crypt->ops->decrypt_msdu)
return 0;
- if (ieee->hwsec_active)
- {
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb+ MAX_DEV_ADDR_SIZE);
+ if (ieee->hwsec_active) {
+ struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->bHwSec = 1;
}
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
atomic_inc(&crypt->refcnt);
@@ -410,7 +408,7 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, struct sk_buff *s
/* this function is stolen from ipw2200 driver*/
-#define IEEE_PACKET_RETRY_TIME (5*HZ)
+#define IEEE_PACKET_RETRY_TIME (5 * HZ)
static int is_duplicate_packet(struct ieee80211_device *ieee,
struct rtl_80211_hdr_4addr *header)
{
@@ -426,18 +424,18 @@ static int is_duplicate_packet(struct ieee80211_device *ieee,
//TO2DS and QoS
- if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
- hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)header;
- tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
- } else if(IEEE80211_QOS_HAS_SEQ(fc)) { //QoS
- hdr_3addrqos = (struct rtl_80211_hdr_3addrqos *)header;
- tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
+ if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
+ hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)header;
+ tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
+ tid = UP2AC(tid);
+ tid++;
+ } else if (IEEE80211_QOS_HAS_SEQ(fc)) { //QoS
+ hdr_3addrqos = (struct rtl_80211_hdr_3addrqos *)header;
+ tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID;
+ tid = UP2AC(tid);
+ tid++;
} else { // no QoS
- tid = 0;
+ tid = 0;
}
switch (ieee->iw_mode) {
@@ -507,8 +505,7 @@ drop:
static bool AddReorderEntry(struct rx_ts_record *pTS, struct rx_reorder_entry *pReorderEntry)
{
struct list_head *pList = &pTS->rx_pending_pkt_list;
- while(pList->next != &pTS->rx_pending_pkt_list)
- {
+ while (pList->next != &pTS->rx_pending_pkt_list) {
if (SN_LESS(pReorderEntry->SeqNum, list_entry(pList->next, struct rx_reorder_entry, List)->SeqNum))
pList = pList->next;
else if (SN_EQUAL(pReorderEntry->SeqNum, list_entry(pList->next, struct rx_reorder_entry, List)->SeqNum))
@@ -524,17 +521,16 @@ static bool AddReorderEntry(struct rx_ts_record *pTS, struct rx_reorder_entry *p
return true;
}
-void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb **prxbIndicateArray,u8 index)
+void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb **prxbIndicateArray, u8 index)
{
- u8 i = 0 , j=0;
+ u8 i = 0, j = 0;
u16 ethertype;
// if(index > 1)
// IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): hahahahhhh, We indicate packet from reorder list, index is %u\n",__func__,index);
- for(j = 0; j<index; j++)
- {
+ for (j = 0; j < index; j++) {
//added by amy for reorder
struct ieee80211_rxb *prxb = prxbIndicateArray[j];
- for(i = 0; i<prxb->nr_subframes; i++) {
+ for (i = 0; i < prxb->nr_subframes; i++) {
struct sk_buff *sub_skb = prxb->subframes[i];
/* convert hdr + possible LLC headers into Ethernet header */
@@ -585,7 +581,7 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
u16 WinEnd = (pTS->rx_indicate_seq + WinSize - 1) % 4096;
u8 index = 0;
bool bMatchWinStart = false, bPktInBuf = false;
- IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): Seq is %d,pTS->rx_indicate_seq is %d, WinSize is %d\n",__func__,SeqNum,pTS->rx_indicate_seq,WinSize);
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s(): Seq is %d,pTS->rx_indicate_seq is %d, WinSize is %d\n", __func__, SeqNum, pTS->rx_indicate_seq, WinSize);
prxbIndicateArray = kmalloc_array(REORDER_WIN_SIZE,
sizeof(struct ieee80211_rxb *),
@@ -599,12 +595,12 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
/* Drop out the packet which SeqNum is smaller than WinStart */
if (SN_LESS(SeqNum, pTS->rx_indicate_seq)) {
- IEEE80211_DEBUG(IEEE80211_DL_REORDER,"Packet Drop! IndicateSeq: %d, NewSeq: %d\n",
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Packet Drop! IndicateSeq: %d, NewSeq: %d\n",
pTS->rx_indicate_seq, SeqNum);
pHTInfo->RxReorderDropCounter++;
{
int i;
- for(i =0; i < prxb->nr_subframes; i++) {
+ for (i = 0; i < prxb->nr_subframes; i++) {
dev_kfree_skb(prxb->subframes[i]);
}
kfree(prxb);
@@ -620,16 +616,16 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
* 1. Incoming SeqNum is equal to WinStart =>Window shift 1
* 2. Incoming SeqNum is larger than the WinEnd => Window shift N
*/
- if(SN_EQUAL(SeqNum, pTS->rx_indicate_seq)) {
+ if (SN_EQUAL(SeqNum, pTS->rx_indicate_seq)) {
pTS->rx_indicate_seq = (pTS->rx_indicate_seq + 1) % 4096;
bMatchWinStart = true;
- } else if(SN_LESS(WinEnd, SeqNum)) {
- if(SeqNum >= (WinSize - 1)) {
- pTS->rx_indicate_seq = SeqNum + 1 -WinSize;
+ } else if (SN_LESS(WinEnd, SeqNum)) {
+ if (SeqNum >= (WinSize - 1)) {
+ pTS->rx_indicate_seq = SeqNum + 1 - WinSize;
} else {
pTS->rx_indicate_seq = 4095 - (WinSize - (SeqNum + 1)) + 1;
}
- IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Window Shift! IndicateSeq: %d, NewSeq: %d\n",pTS->rx_indicate_seq, SeqNum);
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Window Shift! IndicateSeq: %d, NewSeq: %d\n", pTS->rx_indicate_seq, SeqNum);
}
/*
@@ -641,7 +637,7 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
* 1. All packets with SeqNum smaller than WinStart => Indicate
* 2. All packets with SeqNum larger than or equal to WinStart => Buffer it.
*/
- if(bMatchWinStart) {
+ if (bMatchWinStart) {
/* Current packet is going to be indicated.*/
IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Packets indication!! IndicateSeq: %d, NewSeq: %d\n",\
pTS->rx_indicate_seq, SeqNum);
@@ -651,7 +647,7 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
} else {
/* Current packet is going to be inserted into pending list.*/
//IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to ordered list\n",__func__);
- if(!list_empty(&ieee->RxReorder_Unused_List)) {
+ if (!list_empty(&ieee->RxReorder_Unused_List)) {
pReorderEntry = list_entry(ieee->RxReorder_Unused_List.next, struct rx_reorder_entry, List);
list_del_init(&pReorderEntry->List);
@@ -660,13 +656,13 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
pReorderEntry->prxb = prxb;
// IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): pREorderEntry->SeqNum is %d\n",__func__,pReorderEntry->SeqNum);
- if(!AddReorderEntry(pTS, pReorderEntry)) {
+ if (!AddReorderEntry(pTS, pReorderEntry)) {
IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n",
__func__, pTS->rx_indicate_seq, SeqNum);
- list_add_tail(&pReorderEntry->List,&ieee->RxReorder_Unused_List);
+ list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List);
{
int i;
- for(i =0; i < prxb->nr_subframes; i++) {
+ for (i = 0; i < prxb->nr_subframes; i++) {
dev_kfree_skb(prxb->subframes[i]);
}
kfree(prxb);
@@ -674,10 +670,9 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
}
} else {
IEEE80211_DEBUG(IEEE80211_DL_REORDER,
- "Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n",pTS->rx_indicate_seq, SeqNum);
+ "Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n", pTS->rx_indicate_seq, SeqNum);
}
- }
- else {
+ } else {
/*
* Packets are dropped if there is not enough reorder entries.
* This part shall be modified!! We can just indicate all the
@@ -686,7 +681,7 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): There is no reorder entry!! Packet is dropped!!\n");
{
int i;
- for(i =0; i < prxb->nr_subframes; i++) {
+ for (i = 0; i < prxb->nr_subframes; i++) {
dev_kfree_skb(prxb->subframes[i]);
}
kfree(prxb);
@@ -696,12 +691,11 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
}
/* Check if there is any packet need indicate.*/
- while(!list_empty(&pTS->rx_pending_pkt_list)) {
- IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): start RREORDER indicate\n",__func__);
+ while (!list_empty(&pTS->rx_pending_pkt_list)) {
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s(): start RREORDER indicate\n", __func__);
pReorderEntry = list_entry(pTS->rx_pending_pkt_list.prev, struct rx_reorder_entry, List);
if (SN_LESS(pReorderEntry->SeqNum, pTS->rx_indicate_seq) ||
- SN_EQUAL(pReorderEntry->SeqNum, pTS->rx_indicate_seq))
- {
+ SN_EQUAL(pReorderEntry->SeqNum, pTS->rx_indicate_seq)) {
/* This protect buffer from overflow. */
if (index >= REORDER_WIN_SIZE) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Buffer overflow!! \n");
@@ -711,15 +705,15 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
list_del_init(&pReorderEntry->List);
- if(SN_EQUAL(pReorderEntry->SeqNum, pTS->rx_indicate_seq))
+ if (SN_EQUAL(pReorderEntry->SeqNum, pTS->rx_indicate_seq))
pTS->rx_indicate_seq = (pTS->rx_indicate_seq + 1) % 4096;
- IEEE80211_DEBUG(IEEE80211_DL_REORDER,"Packets indication!! IndicateSeq: %d, NewSeq: %d\n",pTS->rx_indicate_seq, SeqNum);
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Packets indication!! IndicateSeq: %d, NewSeq: %d\n", pTS->rx_indicate_seq, SeqNum);
prxbIndicateArray[index] = pReorderEntry->prxb;
// printk("========================>%s(): pReorderEntry->SeqNum is %d\n",__func__,pReorderEntry->SeqNum);
index++;
- list_add_tail(&pReorderEntry->List,&ieee->RxReorder_Unused_List);
+ list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List);
} else {
bPktInBuf = true;
break;
@@ -727,13 +721,13 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
}
/* Handling pending timer. Set this timer to prevent from long time Rx buffering.*/
- if (index>0) {
+ if (index > 0) {
// Cancel previous pending timer.
// del_timer_sync(&pTS->rx_pkt_pending_timer);
pTS->rx_timeout_indicate_seq = 0xffff;
// Indicate packets
- if(index>REORDER_WIN_SIZE){
+ if (index > REORDER_WIN_SIZE) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorder buffer full!! \n");
kfree(prxbIndicateArray);
return;
@@ -743,9 +737,9 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
if (bPktInBuf && pTS->rx_timeout_indicate_seq == 0xffff) {
// Set new pending timer.
- IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): SET rx timeout timer\n", __func__);
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s(): SET rx timeout timer\n", __func__);
pTS->rx_timeout_indicate_seq = pTS->rx_indicate_seq;
- if(timer_pending(&pTS->rx_pkt_pending_timer))
+ if (timer_pending(&pTS->rx_pkt_pending_timer))
del_timer_sync(&pTS->rx_pkt_pending_timer);
pTS->rx_pkt_pending_timer.expires = jiffies +
msecs_to_jiffies(pHTInfo->RxReorderPendingTime);
@@ -762,12 +756,12 @@ static u8 parse_subframe(struct sk_buff *skb,
struct rtl_80211_hdr_3addr *hdr = (struct rtl_80211_hdr_3addr *)skb->data;
u16 fc = le16_to_cpu(hdr->frame_ctl);
- u16 LLCOffset= sizeof(struct rtl_80211_hdr_3addr);
+ u16 LLCOffset = sizeof(struct rtl_80211_hdr_3addr);
u16 ChkLength;
bool bIsAggregateFrame = false;
u16 nSubframe_Length;
u8 nPadding_Length = 0;
- u16 SeqNum=0;
+ u16 SeqNum = 0;
struct sk_buff *sub_skb;
/* just for debug purpose */
@@ -793,7 +787,7 @@ static u8 parse_subframe(struct sk_buff *skb,
skb_pull(skb, LLCOffset);
- if(!bIsAggregateFrame) {
+ if (!bIsAggregateFrame) {
rxb->nr_subframes = 1;
#ifdef JOHN_NOCPY
rxb->subframes[0] = skb;
@@ -801,26 +795,26 @@ static u8 parse_subframe(struct sk_buff *skb,
rxb->subframes[0] = skb_copy(skb, GFP_ATOMIC);
#endif
- memcpy(rxb->src,src,ETH_ALEN);
- memcpy(rxb->dst,dst,ETH_ALEN);
+ memcpy(rxb->src, src, ETH_ALEN);
+ memcpy(rxb->dst, dst, ETH_ALEN);
//IEEE80211_DEBUG_DATA(IEEE80211_DL_RX,skb->data,skb->len);
return 1;
} else {
rxb->nr_subframes = 0;
- memcpy(rxb->src,src,ETH_ALEN);
- memcpy(rxb->dst,dst,ETH_ALEN);
- while(skb->len > ETHERNET_HEADER_SIZE) {
+ memcpy(rxb->src, src, ETH_ALEN);
+ memcpy(rxb->dst, dst, ETH_ALEN);
+ while (skb->len > ETHERNET_HEADER_SIZE) {
/* Offset 12 denote 2 mac address */
nSubframe_Length = *((u16 *)(skb->data + 12));
//==m==>change the length order
- nSubframe_Length = (nSubframe_Length>>8) + (nSubframe_Length<<8);
+ nSubframe_Length = (nSubframe_Length >> 8) + (nSubframe_Length << 8);
- if (skb->len<(ETHERNET_HEADER_SIZE + nSubframe_Length)) {
+ if (skb->len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
printk("%s: A-MSDU parse error!! pRfd->nTotalSubframe : %d\n",\
__func__, rxb->nr_subframes);
- printk("%s: A-MSDU parse error!! Subframe Length: %d\n",__func__, nSubframe_Length);
- printk("nRemain_Length is %d and nSubframe_Length is : %d\n",skb->len,nSubframe_Length);
- printk("The Packet SeqNum is %d\n",SeqNum);
+ printk("%s: A-MSDU parse error!! Subframe Length: %d\n", __func__, nSubframe_Length);
+ printk("nRemain_Length is %d and nSubframe_Length is : %d\n", skb->len, nSubframe_Length);
+ printk("The Packet SeqNum is %d\n", SeqNum);
return 0;
}
@@ -923,9 +917,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
frag = WLAN_GET_SEQ_FRAG(sc);
hdrlen = ieee80211_get_hdrlen(fc);
- if (HTCCheck(ieee, skb->data))
- {
- if(net_ratelimit())
+ if (HTCCheck(ieee, skb->data)) {
+ if (net_ratelimit())
printk("find HTCControl\n");
hdrlen += 4;
rx_stats->bContainHTC = true;
@@ -972,7 +965,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
* stations that do not support WEP key mapping). */
if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
- (void) hostap_handle_sta_crypto(local, hdr, &crypt,
+ (void)hostap_handle_sta_crypto(local, hdr, &crypt,
&sta);
#endif
@@ -998,39 +991,32 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
goto rx_dropped;
// if QoS enabled, should check the sequence for each of the AC
- if ((!ieee->pHTInfo->bCurRxReorderEnable) || !ieee->current_network.qos_data.active|| !IsDataFrame(skb->data) || IsLegacyDataFrame(skb->data)) {
+ if ((!ieee->pHTInfo->bCurRxReorderEnable) || !ieee->current_network.qos_data.active || !IsDataFrame(skb->data) || IsLegacyDataFrame(skb->data)) {
if (is_duplicate_packet(ieee, hdr))
- goto rx_dropped;
+ goto rx_dropped;
- }
- else
- {
+ } else {
struct rx_ts_record *pRxTS = NULL;
//IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): QOS ENABLE AND RECEIVE QOS DATA , we will get Ts, tid:%d\n",__func__, tid);
- if(GetTs(
+ if (GetTs(
ieee,
- (struct ts_common_info **) &pRxTS,
+ (struct ts_common_info **)&pRxTS,
hdr->addr2,
Frame_QoSTID((u8 *)(skb->data)),
RX_DIR,
- true))
- {
+ true)) {
// IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): pRxTS->rx_last_frag_num is %d,frag is %d,pRxTS->rx_last_seq_num is %d,seq is %d\n",__func__,pRxTS->rx_last_frag_num,frag,pRxTS->rx_last_seq_num,WLAN_GET_SEQ_SEQ(sc));
- if ((fc & (1<<11)) &&
+ if ((fc & (1 << 11)) &&
(frag == pRxTS->rx_last_frag_num) &&
(WLAN_GET_SEQ_SEQ(sc) == pRxTS->rx_last_seq_num)) {
goto rx_dropped;
- }
- else
- {
+ } else {
pRxTS->rx_last_frag_num = frag;
pRxTS->rx_last_seq_num = WLAN_GET_SEQ_SEQ(sc);
}
- }
- else
- {
- IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s(): No TS!! Skip the check!!\n",__func__);
+ } else {
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s(): No TS!! Skip the check!!\n", __func__);
goto rx_dropped;
}
}
@@ -1126,14 +1112,13 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* skb: hdr + (possibly fragmented, possibly encrypted) payload */
if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) &&
- (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
- {
+ (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
printk("decrypt frame error\n");
goto rx_dropped;
}
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
/* skb: hdr + (possibly fragmented) plaintext payload */
// PR: FIXME: hostap has additional conditions in the "if" below:
@@ -1185,15 +1170,14 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* this was the last fragment and the frame will be
* delivered, so remove skb from fragment cache */
skb = frag_skb;
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
ieee80211_frag_cache_invalidate(ieee, hdr);
}
/* skb: hdr + (possible reassembled) full MSDU payload; possibly still
* encrypted/authenticated */
if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) &&
- ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
- {
+ ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) {
printk("==>decrypt msdu error\n");
goto rx_dropped;
}
@@ -1202,7 +1186,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
ieee->LinkDetectInfo.NumRecvDataInPeriod++;
ieee->LinkDetectInfo.NumRxOkInPeriod++;
- hdr = (struct rtl_80211_hdr_4addr *) skb->data;
+ hdr = (struct rtl_80211_hdr_4addr *)skb->data;
if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) {
if (/*ieee->ieee802_1x &&*/
ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
@@ -1227,10 +1211,10 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
#ifdef CONFIG_IEEE80211_DEBUG
if (crypt && !(fc & IEEE80211_FCTL_WEP) &&
ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
- struct eapol *eap = (struct eapol *)(skb->data +
- 24);
- IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n",
- eap_get_type(eap->type));
+ struct eapol *eap = (struct eapol *)(skb->data +
+ 24);
+ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n",
+ eap_get_type(eap->type));
}
#endif
@@ -1250,13 +1234,11 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
*/
//added by amy for reorder
if (ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data)
- && !is_multicast_ether_addr(hdr->addr1))
- {
+ && !is_multicast_ether_addr(hdr->addr1)) {
TID = Frame_QoSTID(skb->data);
SeqNum = WLAN_GET_SEQ_SEQ(sc);
- GetTs(ieee,(struct ts_common_info **) &pTS,hdr->addr2,TID,RX_DIR,true);
- if (TID !=0 && TID !=3)
- {
+ GetTs(ieee, (struct ts_common_info **)&pTS, hdr->addr2, TID, RX_DIR, true);
+ if (TID != 0 && TID != 3) {
ieee->bis_any_nonbepkts = true;
}
}
@@ -1270,7 +1252,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* qos data packets & reserved bit is 1 */
if (parse_subframe(skb, rx_stats, rxb, src, dst) == 0) {
/* only to free rxb, and not submit the packets to upper layer */
- for(i =0; i < rxb->nr_subframes; i++) {
+ for (i = 0; i < rxb->nr_subframes; i++) {
dev_kfree_skb(rxb->subframes[i]);
}
kfree(rxb);
@@ -1281,7 +1263,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
//added by amy for reorder
if (!ieee->pHTInfo->bCurRxReorderEnable || !pTS) {
//added by amy for reorder
- for(i = 0; i<rxb->nr_subframes; i++) {
+ for (i = 0; i < rxb->nr_subframes; i++) {
struct sk_buff *sub_skb = rxb->subframes[i];
if (sub_skb) {
@@ -1324,10 +1306,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
kfree(rxb);
rxb = NULL;
- }
- else
- {
- IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): REORDER ENABLE AND PTS not NULL, and we will enter RxReorderIndicatePacket()\n",__func__);
+ } else {
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s(): REORDER ENABLE AND PTS not NULL, and we will enter RxReorderIndicatePacket()\n", __func__);
RxReorderIndicatePacket(ieee, rxb, pTS, SeqNum);
}
#ifndef JOHN_NOCPY
@@ -1407,10 +1387,9 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
/*
* Parse a QoS information element
*/
-static int ieee80211_read_qos_info_element(struct
- ieee80211_qos_information_element
- *element_info, struct ieee80211_info_element
- *info_element)
+static int ieee80211_read_qos_info_element(
+ struct ieee80211_qos_information_element *element_info,
+ struct ieee80211_info_element *info_element)
{
int ret = 0;
u16 size = sizeof(struct ieee80211_qos_information_element) - 2;
@@ -1438,11 +1417,9 @@ static int ieee80211_read_qos_info_element(struct
/*
* Write QoS parameters from the ac parameters.
*/
-static int ieee80211_qos_convert_ac_to_parameters(struct
- ieee80211_qos_parameter_info
- *param_elm, struct
- ieee80211_qos_parameters
- *qos_param)
+static int ieee80211_qos_convert_ac_to_parameters(
+ struct ieee80211_qos_parameter_info *param_elm,
+ struct ieee80211_qos_parameters *qos_param)
{
int i;
struct ieee80211_qos_ac_parameter *ac_params;
@@ -1455,12 +1432,12 @@ static int ieee80211_qos_convert_ac_to_parameters(struct
aci = (ac_params->aci_aifsn & 0x60) >> 5;
- if(aci >= QOS_QUEUE_NUM)
+ if (aci >= QOS_QUEUE_NUM)
continue;
qos_param->aifs[aci] = (ac_params->aci_aifsn) & 0x0f;
/* WMM spec P.11: The minimum value for AIFSN shall be 2 */
- qos_param->aifs[aci] = (qos_param->aifs[aci] < 2) ? 2:qos_param->aifs[aci];
+ qos_param->aifs[aci] = (qos_param->aifs[aci] < 2) ? 2 : qos_param->aifs[aci];
qos_param->cw_min[aci] =
cpu_to_le16(ac_params->ecw_min_max & 0x0F);
@@ -1561,15 +1538,12 @@ static inline void ieee80211_extract_country_ie(
u8 *addr2
)
{
- if (IS_DOT11D_ENABLE(ieee))
- {
- if (info_element->len!= 0)
- {
+ if (IS_DOT11D_ENABLE(ieee)) {
+ if (info_element->len != 0) {
memcpy(network->CountryIeBuf, info_element->data, info_element->len);
network->CountryIeLen = info_element->len;
- if (!IS_COUNTRY_IE_VALID(ieee))
- {
+ if (!IS_COUNTRY_IE_VALID(ieee)) {
dot11d_update_country_ie(ieee, addr2, info_element->len, info_element->data);
}
}
@@ -1579,8 +1553,7 @@ static inline void ieee80211_extract_country_ie(
// some AP (e.g. Cisco 1242) don't include country IE in their
// probe response frame.
//
- if (IS_EQUAL_CIE_SRC(ieee, addr2) )
- {
+ if (IS_EQUAL_CIE_SRC(ieee, addr2)) {
UPDATE_CIE_WATCHDOG(ieee);
}
}
@@ -1595,9 +1568,9 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
{
u8 i;
short offset;
- u16 tmp_htcap_len=0;
- u16 tmp_htinfo_len=0;
- u16 ht_realtek_agg_len=0;
+ u16 tmp_htcap_len = 0;
+ u16 tmp_htinfo_len = 0;
+ u16 ht_realtek_agg_len = 0;
u8 ht_realtek_agg_buf[MAX_IE_LEN];
// u16 broadcom_len = 0;
#ifdef CONFIG_IEEE80211_DEBUG
@@ -1628,7 +1601,7 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
}
network->ssid_len = min(info_element->len,
- (u8) IW_ESSID_MAX_SIZE);
+ (u8)IW_ESSID_MAX_SIZE);
memcpy(network->ssid, info_element->data, network->ssid_len);
if (network->ssid_len < IW_ESSID_MAX_SIZE)
memset(network->ssid + network->ssid_len, 0,
@@ -1707,14 +1680,14 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
break;
case MFIE_TYPE_TIM:
- if(info_element->len < 4)
+ if (info_element->len < 4)
break;
network->tim.tim_count = info_element->data[0];
network->tim.tim_period = info_element->data[1];
network->dtim_period = info_element->data[1];
- if(ieee->state != IEEE80211_LINKED)
+ if (ieee->state != IEEE80211_LINKED)
break;
network->last_dtim_sta_time[0] = stats->mac_time[0];
@@ -1722,22 +1695,22 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
network->dtim_data = IEEE80211_DTIM_VALID;
- if(info_element->data[0] != 0)
+ if (info_element->data[0] != 0)
break;
- if(info_element->data[2] & 1)
+ if (info_element->data[2] & 1)
network->dtim_data |= IEEE80211_DTIM_MBCAST;
- offset = (info_element->data[2] >> 1)*2;
+ offset = (info_element->data[2] >> 1) * 2;
- if(ieee->assoc_id < 8*offset ||
- ieee->assoc_id > 8*(offset + info_element->len -3))
+ if (ieee->assoc_id < 8 * offset ||
+ ieee->assoc_id > 8 * (offset + info_element->len - 3))
break;
offset = (ieee->assoc_id / 8) - offset;// + ((aid % 8)? 0 : 1) ;
- if(info_element->data[3+offset] & (1<<(ieee->assoc_id%8)))
+ if (info_element->data[3 + offset] & (1 << (ieee->assoc_id % 8)))
network->dtim_data |= IEEE80211_DTIM_UCAST;
//IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n");
@@ -1790,66 +1763,66 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
#endif
//for HTcap and HTinfo parameters
- if(tmp_htcap_len == 0){
- if(info_element->len >= 4 &&
+ if (tmp_htcap_len == 0) {
+ if (info_element->len >= 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x90 &&
info_element->data[2] == 0x4c &&
info_element->data[3] == 0x033){
- tmp_htcap_len = min(info_element->len,(u8)MAX_IE_LEN);
- if(tmp_htcap_len != 0){
- network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC;
- network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf)?\
- sizeof(network->bssht.bdHTCapBuf):tmp_htcap_len;
- memcpy(network->bssht.bdHTCapBuf,info_element->data,network->bssht.bdHTCapLen);
- }
+ tmp_htcap_len = min(info_element->len, (u8)MAX_IE_LEN);
+ if (tmp_htcap_len != 0) {
+ network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC;
+ network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf) ? \
+ sizeof(network->bssht.bdHTCapBuf) : tmp_htcap_len;
+ memcpy(network->bssht.bdHTCapBuf, info_element->data, network->bssht.bdHTCapLen);
+ }
}
- if(tmp_htcap_len != 0)
+ if (tmp_htcap_len != 0)
network->bssht.bdSupportHT = true;
else
network->bssht.bdSupportHT = false;
}
- if(tmp_htinfo_len == 0){
- if(info_element->len >= 4 &&
+ if (tmp_htinfo_len == 0) {
+ if (info_element->len >= 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x90 &&
info_element->data[2] == 0x4c &&
info_element->data[3] == 0x034){
- tmp_htinfo_len = min(info_element->len,(u8)MAX_IE_LEN);
- if(tmp_htinfo_len != 0){
- network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC;
- if(tmp_htinfo_len){
- network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf)?\
- sizeof(network->bssht.bdHTInfoBuf):tmp_htinfo_len;
- memcpy(network->bssht.bdHTInfoBuf,info_element->data,network->bssht.bdHTInfoLen);
- }
-
+ tmp_htinfo_len = min(info_element->len, (u8)MAX_IE_LEN);
+ if (tmp_htinfo_len != 0) {
+ network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC;
+ if (tmp_htinfo_len) {
+ network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf) ? \
+ sizeof(network->bssht.bdHTInfoBuf) : tmp_htinfo_len;
+ memcpy(network->bssht.bdHTInfoBuf, info_element->data, network->bssht.bdHTInfoLen);
}
+ }
+
}
}
- if(ieee->aggregation){
- if(network->bssht.bdSupportHT){
- if(info_element->len >= 4 &&
+ if (ieee->aggregation) {
+ if (network->bssht.bdSupportHT) {
+ if (info_element->len >= 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0xe0 &&
info_element->data[2] == 0x4c &&
info_element->data[3] == 0x02){
- ht_realtek_agg_len = min(info_element->len,(u8)MAX_IE_LEN);
- memcpy(ht_realtek_agg_buf,info_element->data,info_element->len);
+ ht_realtek_agg_len = min(info_element->len, (u8)MAX_IE_LEN);
+ memcpy(ht_realtek_agg_buf, info_element->data, info_element->len);
}
- if(ht_realtek_agg_len >= 5){
+ if (ht_realtek_agg_len >= 5) {
network->bssht.bdRT2RTAggregation = true;
- if((ht_realtek_agg_buf[4] == 1) && (ht_realtek_agg_buf[5] & 0x02))
- network->bssht.bdRT2RTLongSlotTime = true;
+ if ((ht_realtek_agg_buf[4] == 1) && (ht_realtek_agg_buf[5] & 0x02))
+ network->bssht.bdRT2RTLongSlotTime = true;
}
}
@@ -1870,78 +1843,63 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
info_element->data[1] == 0x10 &&
info_element->data[2] == 0x18)){
- network->broadcom_cap_exist = true;
+ network->broadcom_cap_exist = true;
}
}
- if(info_element->len >= 3 &&
+ if (info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x0c &&
- info_element->data[2] == 0x43)
- {
+ info_element->data[2] == 0x43) {
network->ralink_cap_exist = true;
- }
- else
+ } else
network->ralink_cap_exist = false;
//added by amy for atheros AP
- if((info_element->len >= 3 &&
+ if ((info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x03 &&
info_element->data[2] == 0x7f) ||
(info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x13 &&
- info_element->data[2] == 0x74))
- {
- printk("========>%s(): athros AP is exist\n",__func__);
+ info_element->data[2] == 0x74)) {
+ printk("========>%s(): athros AP is exist\n", __func__);
network->atheros_cap_exist = true;
- }
- else
+ } else
network->atheros_cap_exist = false;
- if(info_element->len >= 3 &&
+ if (info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x40 &&
- info_element->data[2] == 0x96)
- {
+ info_element->data[2] == 0x96) {
network->cisco_cap_exist = true;
- }
- else
+ } else
network->cisco_cap_exist = false;
//added by amy for LEAP of cisco
if (info_element->len > 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x40 &&
info_element->data[2] == 0x96 &&
- info_element->data[3] == 0x01)
- {
- if(info_element->len == 6)
- {
+ info_element->data[3] == 0x01) {
+ if (info_element->len == 6) {
memcpy(network->CcxRmState, &info_element[4], 2);
- if(network->CcxRmState[0] != 0)
- {
+ if (network->CcxRmState[0] != 0)
network->bCcxRmEnable = true;
- }
else
network->bCcxRmEnable = false;
//
// CCXv4 Table 59-1 MBSSID Masks.
//
network->MBssidMask = network->CcxRmState[1] & 0x07;
- if(network->MBssidMask != 0)
- {
+ if (network->MBssidMask != 0) {
network->bMBssidValid = true;
network->MBssidMask = 0xff << (network->MBssidMask);
ether_addr_copy(network->MBssid, network->bssid);
network->MBssid[5] &= network->MBssidMask;
- }
- else
- {
+ } else {
network->bMBssidValid = false;
}
- }
- else
- {
+ } else {
network->bCcxRmEnable = false;
}
}
@@ -1949,15 +1907,11 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x40 &&
info_element->data[2] == 0x96 &&
- info_element->data[3] == 0x03)
- {
- if(info_element->len == 5)
- {
+ info_element->data[3] == 0x03) {
+ if (info_element->len == 5) {
network->bWithCcxVerNum = true;
network->BssCcxVerNumber = info_element->data[4];
- }
- else
- {
+ } else {
network->bWithCcxVerNum = false;
network->BssCcxVerNumber = 0;
}
@@ -1977,19 +1931,18 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
case MFIE_TYPE_HT_CAP:
IEEE80211_DEBUG_SCAN("MFIE_TYPE_HT_CAP: %d bytes\n",
info_element->len);
- tmp_htcap_len = min(info_element->len,(u8)MAX_IE_LEN);
- if(tmp_htcap_len != 0){
+ tmp_htcap_len = min(info_element->len, (u8)MAX_IE_LEN);
+ if (tmp_htcap_len != 0) {
network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC;
- network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf)?\
- sizeof(network->bssht.bdHTCapBuf):tmp_htcap_len;
- memcpy(network->bssht.bdHTCapBuf,info_element->data,network->bssht.bdHTCapLen);
+ network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf) ? \
+ sizeof(network->bssht.bdHTCapBuf) : tmp_htcap_len;
+ memcpy(network->bssht.bdHTCapBuf, info_element->data, network->bssht.bdHTCapLen);
//If peer is HT, but not WMM, call QosSetLegacyWMMParamWithHT()
// windows driver will update WMM parameters each beacon received once connected
// Linux driver is a bit different.
network->bssht.bdSupportHT = true;
- }
- else
+ } else
network->bssht.bdSupportHT = false;
break;
@@ -1997,37 +1950,31 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
case MFIE_TYPE_HT_INFO:
IEEE80211_DEBUG_SCAN("MFIE_TYPE_HT_INFO: %d bytes\n",
info_element->len);
- tmp_htinfo_len = min(info_element->len,(u8)MAX_IE_LEN);
- if(tmp_htinfo_len){
+ tmp_htinfo_len = min(info_element->len, (u8)MAX_IE_LEN);
+ if (tmp_htinfo_len) {
network->bssht.bdHTSpecVer = HT_SPEC_VER_IEEE;
- network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf)?\
- sizeof(network->bssht.bdHTInfoBuf):tmp_htinfo_len;
- memcpy(network->bssht.bdHTInfoBuf,info_element->data,network->bssht.bdHTInfoLen);
+ network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf) ? \
+ sizeof(network->bssht.bdHTInfoBuf) : tmp_htinfo_len;
+ memcpy(network->bssht.bdHTInfoBuf, info_element->data, network->bssht.bdHTInfoLen);
}
break;
case MFIE_TYPE_AIRONET:
IEEE80211_DEBUG_SCAN("MFIE_TYPE_AIRONET: %d bytes\n",
info_element->len);
- if(info_element->len >IE_CISCO_FLAG_POSITION)
- {
+ if (info_element->len > IE_CISCO_FLAG_POSITION) {
network->bWithAironetIE = true;
// CCX 1 spec v1.13, A01.1 CKIP Negotiation (page23):
// "A Cisco access point advertises support for CKIP in beacon and probe response packets,
// by adding an Aironet element and setting one or both of the CKIP negotiation bits."
- if( (info_element->data[IE_CISCO_FLAG_POSITION]&SUPPORT_CKIP_MIC) ||
- (info_element->data[IE_CISCO_FLAG_POSITION]&SUPPORT_CKIP_PK) )
- {
+ if ((info_element->data[IE_CISCO_FLAG_POSITION] & SUPPORT_CKIP_MIC) ||
+ (info_element->data[IE_CISCO_FLAG_POSITION] & SUPPORT_CKIP_PK)) {
network->bCkipSupported = true;
- }
- else
- {
+ } else {
network->bCkipSupported = false;
}
- }
- else
- {
+ } else {
network->bWithAironetIE = false;
network->bCkipSupported = false;
}
@@ -2057,13 +2004,10 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
data[info_element->len];
}
- if(!network->atheros_cap_exist && !network->broadcom_cap_exist &&
- !network->cisco_cap_exist && !network->ralink_cap_exist && !network->bssht.bdRT2RTAggregation)
- {
+ if (!network->atheros_cap_exist && !network->broadcom_cap_exist &&
+ !network->cisco_cap_exist && !network->ralink_cap_exist && !network->bssht.bdRT2RTAggregation) {
network->unknown_cap_exist = true;
- }
- else
- {
+ } else {
network->unknown_cap_exist = false;
}
return 0;
@@ -2076,44 +2020,25 @@ static inline u8 ieee80211_SignalStrengthTranslate(
u8 RetSS;
// Step 1. Scale mapping.
- if(CurrSS >= 71 && CurrSS <= 100)
- {
+ if (CurrSS >= 71 && CurrSS <= 100) {
RetSS = 90 + ((CurrSS - 70) / 3);
- }
- else if(CurrSS >= 41 && CurrSS <= 70)
- {
+ } else if (CurrSS >= 41 && CurrSS <= 70) {
RetSS = 78 + ((CurrSS - 40) / 3);
- }
- else if(CurrSS >= 31 && CurrSS <= 40)
- {
+ } else if (CurrSS >= 31 && CurrSS <= 40) {
RetSS = 66 + (CurrSS - 30);
- }
- else if(CurrSS >= 21 && CurrSS <= 30)
- {
+ } else if (CurrSS >= 21 && CurrSS <= 30) {
RetSS = 54 + (CurrSS - 20);
- }
- else if(CurrSS >= 5 && CurrSS <= 20)
- {
+ } else if (CurrSS >= 5 && CurrSS <= 20) {
RetSS = 42 + (((CurrSS - 5) * 2) / 3);
- }
- else if(CurrSS == 4)
- {
+ } else if (CurrSS == 4) {
RetSS = 36;
- }
- else if(CurrSS == 3)
- {
+ } else if (CurrSS == 3) {
RetSS = 27;
- }
- else if(CurrSS == 2)
- {
+ } else if (CurrSS == 2) {
RetSS = 18;
- }
- else if(CurrSS == 1)
- {
+ } else if (CurrSS == 1) {
RetSS = 9;
- }
- else
- {
+ } else {
RetSS = CurrSS;
}
//RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS));
@@ -2193,7 +2118,7 @@ static inline int ieee80211_network_init(
network->rsn_ie_len = 0;
if (ieee80211_parse_info_param
- (ieee,beacon->info_element, stats->len - sizeof(*beacon), network, stats))
+ (ieee, beacon->info_element, stats->len - sizeof(*beacon), network, stats))
return 1;
network->mode = 0;
@@ -2215,10 +2140,10 @@ static inline int ieee80211_network_init(
return 1;
}
- if(network->bssht.bdSupportHT){
- if(network->mode == IEEE_A)
+ if (network->bssht.bdSupportHT) {
+ if (network->mode == IEEE_A)
network->mode = IEEE_N_5G;
- else if(network->mode & (IEEE_G | IEEE_B))
+ else if (network->mode & (IEEE_G | IEEE_B))
network->mode = IEEE_N_24G;
}
if (ieee80211_is_empty_essid(network->ssid, network->ssid_len))
@@ -2226,7 +2151,7 @@ static inline int ieee80211_network_init(
stats->signal = 30 + (stats->SignalStrength * 70) / 100;
//stats->signal = ieee80211_SignalStrengthTranslate(stats->signal);
- stats->noise = ieee80211_translate_todbm((u8)(100-stats->signal)) -25;
+ stats->noise = ieee80211_translate_todbm((u8)(100 - stats->signal)) - 25;
memcpy(&network->stats, stats, sizeof(network->stats));
@@ -2264,8 +2189,7 @@ static inline void update_network(struct ieee80211_network *dst,
dst->rates_len = src->rates_len;
memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
dst->rates_ex_len = src->rates_ex_len;
- if (src->ssid_len > 0)
- {
+ if (src->ssid_len > 0) {
memset(dst->ssid, 0, dst->ssid_len);
dst->ssid_len = src->ssid_len;
memcpy(dst->ssid, src->ssid, src->ssid_len);
@@ -2274,8 +2198,7 @@ static inline void update_network(struct ieee80211_network *dst,
dst->flags = src->flags;
dst->time_stamp[0] = src->time_stamp[0];
dst->time_stamp[1] = src->time_stamp[1];
- if (src->flags & NETWORK_HAS_ERP_VALUE)
- {
+ if (src->flags & NETWORK_HAS_ERP_VALUE) {
dst->erp_value = src->erp_value;
dst->berp_info_valid = src->berp_info_valid = true;
}
@@ -2290,10 +2213,10 @@ static inline void update_network(struct ieee80211_network *dst,
dst->bssht.bdSupportHT = src->bssht.bdSupportHT;
dst->bssht.bdRT2RTAggregation = src->bssht.bdRT2RTAggregation;
- dst->bssht.bdHTCapLen= src->bssht.bdHTCapLen;
- memcpy(dst->bssht.bdHTCapBuf,src->bssht.bdHTCapBuf,src->bssht.bdHTCapLen);
- dst->bssht.bdHTInfoLen= src->bssht.bdHTInfoLen;
- memcpy(dst->bssht.bdHTInfoBuf,src->bssht.bdHTInfoBuf,src->bssht.bdHTInfoLen);
+ dst->bssht.bdHTCapLen = src->bssht.bdHTCapLen;
+ memcpy(dst->bssht.bdHTCapBuf, src->bssht.bdHTCapBuf, src->bssht.bdHTCapLen);
+ dst->bssht.bdHTInfoLen = src->bssht.bdHTInfoLen;
+ memcpy(dst->bssht.bdHTInfoBuf, src->bssht.bdHTInfoBuf, src->bssht.bdHTInfoLen);
dst->bssht.bdHTSpecVer = src->bssht.bdHTSpecVer;
dst->bssht.bdRT2RTLongSlotTime = src->bssht.bdRT2RTLongSlotTime;
dst->broadcom_cap_exist = src->broadcom_cap_exist;
@@ -2312,7 +2235,7 @@ static inline void update_network(struct ieee80211_network *dst,
qos_active = dst->qos_data.active;
//old_param = dst->qos_data.old_param_count;
old_param = dst->qos_data.param_count;
- if(dst->flags & NETWORK_HAS_QOS_MASK)
+ if (dst->flags & NETWORK_HAS_QOS_MASK)
memcpy(&dst->qos_data, &src->qos_data,
sizeof(struct ieee80211_qos_data));
else {
@@ -2322,7 +2245,7 @@ static inline void update_network(struct ieee80211_network *dst,
if (dst->qos_data.supported == 1) {
dst->QoS_Enable = 1;
- if(dst->ssid_len)
+ if (dst->ssid_len)
IEEE80211_DEBUG_QOS
("QoS the network %s is QoS supported\n",
dst->ssid);
@@ -2335,11 +2258,11 @@ static inline void update_network(struct ieee80211_network *dst,
/* dst->last_associate is not overwritten */
dst->wmm_info = src->wmm_info; //sure to exist in beacon or probe response frame.
- if (src->wmm_param[0].aci_aifsn|| \
- src->wmm_param[1].aci_aifsn|| \
- src->wmm_param[2].aci_aifsn|| \
+ if (src->wmm_param[0].aci_aifsn || \
+ src->wmm_param[1].aci_aifsn || \
+ src->wmm_param[2].aci_aifsn || \
src->wmm_param[3].aci_aifsn) {
- memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN);
+ memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN);
}
//dst->QoS_Enable = src->QoS_Enable;
#ifdef THOMAS_TURBO
@@ -2429,46 +2352,34 @@ static inline void ieee80211_process_probe_response(
if (!is_legal_channel(ieee, network->channel))
goto out;
- if (ieee->bGlobalDomain)
- {
- if (fc == IEEE80211_STYPE_PROBE_RESP)
- {
- // Case 1: Country code
- if(IS_COUNTRY_IE_VALID(ieee) )
- {
+ if (ieee->bGlobalDomain) {
+ if (fc == IEEE80211_STYPE_PROBE_RESP) {
+ if (IS_COUNTRY_IE_VALID(ieee)) {
+ // Case 1: Country code
if (!is_legal_channel(ieee, network->channel)) {
printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network->channel);
goto out;
}
- }
- // Case 2: No any country code.
- else
- {
+ } else {
+ // Case 2: No any country code.
// Filter over channel ch12~14
- if (network->channel > 11)
- {
+ if (network->channel > 11) {
printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network->channel);
goto out;
}
}
- }
- else
- {
- // Case 1: Country code
- if(IS_COUNTRY_IE_VALID(ieee) )
- {
+ } else {
+ if (IS_COUNTRY_IE_VALID(ieee)) {
+ // Case 1: Country code
if (!is_legal_channel(ieee, network->channel)) {
- printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network->channel);
+ printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n", network->channel);
goto out;
}
- }
- // Case 2: No any country code.
- else
- {
+ } else {
+ // Case 2: No any country code.
// Filter over channel ch12~14
- if (network->channel > 14)
- {
- printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network->channel);
+ if (network->channel > 14) {
+ printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n", network->channel);
goto out;
}
}
@@ -2490,19 +2401,17 @@ static inline void ieee80211_process_probe_response(
if (is_same_network(&ieee->current_network, network, ieee)) {
update_network(&ieee->current_network, network);
if ((ieee->current_network.mode == IEEE_N_24G || ieee->current_network.mode == IEEE_G)
- && ieee->current_network.berp_info_valid){
- if(ieee->current_network.erp_value& ERP_UseProtection)
- ieee->current_network.buseprotection = true;
- else
- ieee->current_network.buseprotection = false;
+ && ieee->current_network.berp_info_valid){
+ if (ieee->current_network.erp_value & ERP_UseProtection)
+ ieee->current_network.buseprotection = true;
+ else
+ ieee->current_network.buseprotection = false;
}
- if(is_beacon(beacon->header.frame_ctl))
- {
- if(ieee->state == IEEE80211_LINKED)
+ if (is_beacon(beacon->header.frame_ctl)) {
+ if (ieee->state == IEEE80211_LINKED)
ieee->LinkDetectInfo.NumRecvBcnInPeriod++;
- }
- else //hidden AP
- network->flags = (~NETWORK_EMPTY_ESSID & network->flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags);
+ } else //hidden AP
+ network->flags = (~NETWORK_EMPTY_ESSID & network->flags) | (NETWORK_EMPTY_ESSID & ieee->current_network.flags);
}
list_for_each_entry(target, &ieee->network_list, list) {
@@ -2543,8 +2452,8 @@ static inline void ieee80211_process_probe_response(
#endif
memcpy(target, network, sizeof(*target));
list_add_tail(&target->list, &ieee->network_list);
- if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
- ieee80211_softmac_new_net(ieee,network);
+ if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
+ ieee80211_softmac_new_net(ieee, network);
} else {
IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
escape_essid(target->ssid,
@@ -2559,26 +2468,26 @@ static inline void ieee80211_process_probe_response(
*/
renew = !time_after(target->last_scanned + ieee->scan_age, jiffies);
//YJ,add,080819,for hidden ap
- if(is_beacon(beacon->header.frame_ctl) == 0)
- network->flags = (~NETWORK_EMPTY_ESSID & network->flags)|(NETWORK_EMPTY_ESSID & target->flags);
+ if (is_beacon(beacon->header.frame_ctl) == 0)
+ network->flags = (~NETWORK_EMPTY_ESSID & network->flags) | (NETWORK_EMPTY_ESSID & target->flags);
//if(strncmp(network->ssid, "linksys-c",9) == 0)
// printk("====>2 network->ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network->ssid, network->flags, target->ssid, target->flags);
- if(((network->flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \
+ if (((network->flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \
&& (((network->ssid_len > 0) && (strncmp(target->ssid, network->ssid, network->ssid_len)))\
- ||((ieee->current_network.ssid_len == network->ssid_len) && (strncmp(ieee->current_network.ssid, network->ssid, network->ssid_len) == 0) && (ieee->state == IEEE80211_NOLINK))))
+ || ((ieee->current_network.ssid_len == network->ssid_len) && (strncmp(ieee->current_network.ssid, network->ssid, network->ssid_len) == 0) && (ieee->state == IEEE80211_NOLINK))))
renew = 1;
//YJ,add,080819,for hidden ap,end
update_network(target, network);
- if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE))
- ieee80211_softmac_new_net(ieee,network);
+ if (renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE))
+ ieee80211_softmac_new_net(ieee, network);
}
spin_unlock_irqrestore(&ieee->lock, flags);
if (is_beacon(beacon->header.frame_ctl) && is_same_network(&ieee->current_network, network, ieee) && \
(ieee->state == IEEE80211_LINKED)) {
if (ieee->handle_beacon)
- ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network);
+ ieee->handle_beacon(ieee->dev, beacon, &ieee->current_network);
}
out:
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index e0da0900a4f7..33a6af7aad22 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -743,7 +743,6 @@ static struct sk_buff *ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
if (ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT))
beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
- crypt = ieee->crypt[ieee->tx_keyidx];
if (encrypt)
beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
index 4a8d16a45fc5..b1baaa18b129 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
@@ -42,8 +42,8 @@ int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info
/* if setting by freq convert to channel */
if (fwrq->e == 1) {
- if ((fwrq->m >= (int) 2.412e8 &&
- fwrq->m <= (int) 2.487e8)) {
+ if ((fwrq->m >= (int)2.412e8 &&
+ fwrq->m <= (int)2.487e8)) {
int f = fwrq->m / 100000;
int c = 0;
@@ -92,7 +92,7 @@ int ieee80211_wx_get_freq(struct ieee80211_device *ieee,
if (ieee->current_network.channel == 0)
return -1;
/* NM 0.7.0 will not accept channel any more. */
- fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000;
+ fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel - 1] * 100000;
fwrq->e = 1;
/* fwrq->m = ieee->current_network.channel; */
/* fwrq->e = 0; */
@@ -220,7 +220,7 @@ int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
u32 target_rate = wrqu->bitrate.value;
- ieee->rate = target_rate/100000;
+ ieee->rate = target_rate / 100000;
/* FIXME: we might want to limit rate also in management protocols. */
return 0;
}
@@ -415,9 +415,9 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
if (wrqu->essid.flags && wrqu->essid.length) {
/* first flush current network.ssid */
- len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE;
- strncpy(ieee->current_network.ssid, extra, len+1);
- ieee->current_network.ssid_len = len+1;
+ len = ((wrqu->essid.length - 1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length - 1) : IW_ESSID_MAX_SIZE;
+ strncpy(ieee->current_network.ssid, extra, len + 1);
+ ieee->current_network.ssid_len = len + 1;
ieee->ssid_set = 1;
} else {
ieee->ssid_set = 0;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index fc6eb97801e1..f0b6b8372f91 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -214,7 +214,8 @@ int ieee80211_encrypt_fragment(
}
-void ieee80211_txb_free(struct ieee80211_txb *txb) {
+void ieee80211_txb_free(struct ieee80211_txb *txb)
+{
//int i;
if (unlikely(!txb))
return;
@@ -293,7 +294,7 @@ static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee,
struct tx_ts_record *pTxTs = NULL;
struct rtl_80211_hdr_1addr *hdr = (struct rtl_80211_hdr_1addr *)skb->data;
- if (!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT)
+ if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT)
return;
if (!IsQoSDataFrame(skb->data))
return;
@@ -301,13 +302,6 @@ static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee,
if (is_multicast_ether_addr(hdr->addr1))
return;
//check packet and mode later
-#ifdef TO_DO_LIST
- if (pTcb->PacketLength >= 4096)
- return;
- // For RTL819X, if pairwisekey = wep/tkip, we don't aggrregation.
- if (!Adapter->HalFunc.GetNmodeSupportBySecCfgHandler(Adapter))
- return;
-#endif
if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) {
return;
}
@@ -333,8 +327,7 @@ static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee,
}
}
FORCED_AGG_SETTING:
- switch (pHTInfo->ForcedAMPDUMode )
- {
+ switch (pHTInfo->ForcedAMPDUMode) {
case HT_AGG_AUTO:
break;
@@ -372,7 +365,7 @@ ieee80211_query_HTCapShortGI(struct ieee80211_device *ieee, struct cb_desc *tcb_
tcb_desc->bUseShortGI = false;
- if (!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT)
+ if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT)
return;
if (pHTInfo->bForcedShortGI) {
@@ -380,9 +373,9 @@ ieee80211_query_HTCapShortGI(struct ieee80211_device *ieee, struct cb_desc *tcb_
return;
}
- if ((pHTInfo->bCurBW40MHz==true) && pHTInfo->bCurShortGI40MHz)
+ if ((pHTInfo->bCurBW40MHz == true) && pHTInfo->bCurShortGI40MHz)
tcb_desc->bUseShortGI = true;
- else if ((pHTInfo->bCurBW40MHz==false) && pHTInfo->bCurShortGI20MHz)
+ else if ((pHTInfo->bCurBW40MHz == false) && pHTInfo->bCurShortGI20MHz)
tcb_desc->bUseShortGI = true;
}
@@ -393,16 +386,16 @@ static void ieee80211_query_BandwidthMode(struct ieee80211_device *ieee,
tcb_desc->bPacketBW = false;
- if (!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT)
+ if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT)
return;
if (tcb_desc->bMulticast || tcb_desc->bBroadcast)
return;
- if ((tcb_desc->data_rate & 0x80)==0) // If using legacy rate, it shall use 20MHz channel.
+ if ((tcb_desc->data_rate & 0x80) == 0) // If using legacy rate, it shall use 20MHz channel.
return;
//BandWidthAutoSwitch is for auto switch to 20 or 40 in long distance
- if(pHTInfo->bCurBW40MHz && pHTInfo->bCurTxBW40MHz && !ieee->bandwidth_auto_switch.bforced_tx20Mhz)
+ if (pHTInfo->bCurBW40MHz && pHTInfo->bCurTxBW40MHz && !ieee->bandwidth_auto_switch.bforced_tx20Mhz)
tcb_desc->bPacketBW = true;
return;
}
@@ -418,25 +411,21 @@ static void ieee80211_query_protectionmode(struct ieee80211_device *ieee,
tcb_desc->RTSSC = 0; // 20MHz: Don't care; 40MHz: Duplicate.
tcb_desc->bRTSBW = false; // RTS frame bandwidth is always 20MHz
- if(tcb_desc->bBroadcast || tcb_desc->bMulticast)//only unicast frame will use rts/cts
+ if (tcb_desc->bBroadcast || tcb_desc->bMulticast) //only unicast frame will use rts/cts
return;
- if (is_broadcast_ether_addr(skb->data+16)) //check addr3 as infrastructure add3 is DA.
+ if (is_broadcast_ether_addr(skb->data + 16)) //check addr3 as infrastructure add3 is DA.
return;
- if (ieee->mode < IEEE_N_24G) //b, g mode
- {
+ if (ieee->mode < IEEE_N_24G) /* b, g mode */ {
// (1) RTS_Threshold is compared to the MPDU, not MSDU.
// (2) If there are more than one frag in this MSDU, only the first frag uses protection frame.
// Other fragments are protected by previous fragment.
// So we only need to check the length of first fragment.
- if (skb->len > ieee->rts)
- {
+ if (skb->len > ieee->rts) {
tcb_desc->bRTSEnable = true;
tcb_desc->rts_rate = MGN_24M;
- }
- else if (ieee->current_network.buseprotection)
- {
+ } else if (ieee->current_network.buseprotection) {
// Use CTS-to-SELF in protection mode.
tcb_desc->bRTSEnable = true;
tcb_desc->bCTSEnable = true;
@@ -444,43 +433,35 @@ static void ieee80211_query_protectionmode(struct ieee80211_device *ieee,
}
//otherwise return;
return;
- }
- else
- {// 11n High throughput case.
+ } else { // 11n High throughput case.
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
- while (true)
- {
+ while (true) {
//check ERP protection
- if (ieee->current_network.buseprotection)
- {// CTS-to-SELF
+ if (ieee->current_network.buseprotection) {// CTS-to-SELF
tcb_desc->bRTSEnable = true;
tcb_desc->bCTSEnable = true;
tcb_desc->rts_rate = MGN_24M;
break;
}
//check HT op mode
- if(pHTInfo->bCurrentHTSupport && pHTInfo->bEnableHT)
- {
+ if (pHTInfo->bCurrentHTSupport && pHTInfo->bEnableHT) {
u8 HTOpMode = pHTInfo->CurrentOpMode;
- if((pHTInfo->bCurBW40MHz && (HTOpMode == 2 || HTOpMode == 3)) ||
- (!pHTInfo->bCurBW40MHz && HTOpMode == 3) )
- {
+ if ((pHTInfo->bCurBW40MHz && (HTOpMode == 2 || HTOpMode == 3)) ||
+ (!pHTInfo->bCurBW40MHz && HTOpMode == 3)) {
tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps.
tcb_desc->bRTSEnable = true;
break;
}
}
//check rts
- if (skb->len > ieee->rts)
- {
+ if (skb->len > ieee->rts) {
tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps.
tcb_desc->bRTSEnable = true;
break;
}
//to do list: check MIMO power save condition.
//check AMPDU aggregation for TXOP
- if(tcb_desc->bAMPDUEnable)
- {
+ if (tcb_desc->bAMPDUEnable) {
tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps.
// According to 8190 design, firmware sends CF-End only if RTS/CTS is enabled. However, it degrads
// throughput around 10M, so we disable of this mechanism. 2007.08.03 by Emily
@@ -488,8 +469,7 @@ static void ieee80211_query_protectionmode(struct ieee80211_device *ieee,
break;
}
//check IOT action
- if(pHTInfo->IOTAction & HT_IOT_ACT_FORCED_CTS2SELF)
- {
+ if (pHTInfo->IOTAction & HT_IOT_ACT_FORCED_CTS2SELF) {
tcb_desc->bCTSEnable = true;
tcb_desc->rts_rate = MGN_24M;
tcb_desc->bRTSEnable = true;
@@ -508,7 +488,7 @@ static void ieee80211_query_protectionmode(struct ieee80211_device *ieee,
if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
tcb_desc->bUseShortPreamble = true;
if (ieee->mode == IW_MODE_MASTER)
- goto NO_PROTECTION;
+ goto NO_PROTECTION;
return;
NO_PROTECTION:
tcb_desc->bRTSEnable = false;
@@ -522,27 +502,12 @@ NO_PROTECTION:
static void ieee80211_txrate_selectmode(struct ieee80211_device *ieee,
struct cb_desc *tcb_desc)
{
-#ifdef TO_DO_LIST
- if (!IsDataFrame(pFrame)) {
- pTcb->bTxDisableRateFallBack = true;
- pTcb->bTxUseDriverAssingedRate = true;
- pTcb->RATRIndex = 7;
- return;
- }
-
- if (pMgntInfo->ForcedDataRate!= 0) {
- pTcb->bTxDisableRateFallBack = true;
- pTcb->bTxUseDriverAssingedRate = true;
- return;
- }
-#endif
if (ieee->bTxDisableRateFallBack)
tcb_desc->bTxDisableRateFallBack = true;
if (ieee->bTxUseDriverAssingedRate)
tcb_desc->bTxUseDriverAssingedRate = true;
- if (!tcb_desc->bTxDisableRateFallBack || !tcb_desc->bTxUseDriverAssingedRate)
- {
+ if (!tcb_desc->bTxDisableRateFallBack || !tcb_desc->bTxUseDriverAssingedRate) {
if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC)
tcb_desc->RATRIndex = 0;
}
@@ -553,11 +518,9 @@ static void ieee80211_query_seqnum(struct ieee80211_device *ieee,
{
if (is_multicast_ether_addr(dst))
return;
- if (IsQoSDataFrame(skb->data)) //we deal qos data only
- {
+ if (IsQoSDataFrame(skb->data)) /* we deal qos data only */ {
struct tx_ts_record *pTS = NULL;
- if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, skb->priority, TX_DIR, true))
- {
+ if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, skb->priority, TX_DIR, true)) {
return;
}
pTS->tx_cur_seq = (pTS->tx_cur_seq + 1) % 4096;
@@ -592,7 +555,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* If there is no driver handler to take the TXB, dont' bother
* creating it...
*/
- if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))||
+ if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)) ||
((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) {
printk(KERN_WARNING "%s: No xmit handler.\n",
ieee->dev->name);
@@ -631,7 +594,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* Save source and destination addresses */
memcpy(&dest, skb->data, ETH_ALEN);
- memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN);
+ memcpy(&src, skb->data + ETH_ALEN, ETH_ALEN);
/* Advance the SKB to the start of the payload */
skb_pull(skb, sizeof(struct ethhdr));
@@ -646,7 +609,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
fc = IEEE80211_FTYPE_DATA;
//if(ieee->current_network.QoS_Enable)
- if(qos_actived)
+ if (qos_actived)
fc |= IEEE80211_STYPE_QOS_DATA;
else
fc |= IEEE80211_STYPE_DATA;
@@ -740,7 +703,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
for (i = 0; i < nr_frags; i++) {
skb_frag = txb->fragments[i];
tcb_desc = (struct cb_desc *)(skb_frag->cb + MAX_DEV_ADDR_SIZE);
- if(qos_actived){
+ if (qos_actived) {
skb_frag->priority = skb->priority;//UP2AC(skb->priority);
tcb_desc->queue_index = UP2AC(skb->priority);
} else {
@@ -749,15 +712,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
skb_reserve(skb_frag, ieee->tx_headroom);
- if (encrypt){
+ if (encrypt) {
if (ieee->hwsec_active)
tcb_desc->bHwSec = 1;
else
tcb_desc->bHwSec = 0;
skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
- }
- else
- {
+ } else {
tcb_desc->bHwSec = 0;
}
frag_hdr = skb_put_data(skb_frag, &header, hdr_len);
@@ -775,12 +736,11 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
bytes = bytes_last_frag;
}
//if(ieee->current_network.QoS_Enable)
- if(qos_actived)
- {
+ if (qos_actived) {
// add 1 only indicate to corresponding seq number control 2006/7/12
- frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[UP2AC(skb->priority)+1]<<4 | i);
+ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[UP2AC(skb->priority) + 1] << 4 | i);
} else {
- frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i);
+ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4 | i);
}
/* Put a SNAP header on the first fragment */
@@ -806,17 +766,16 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
skb_put(skb_frag, 4);
}
- if(qos_actived)
- {
- if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF)
- ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0;
- else
- ieee->seq_ctrl[UP2AC(skb->priority) + 1]++;
+ if (qos_actived) {
+ if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF)
+ ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0;
+ else
+ ieee->seq_ctrl[UP2AC(skb->priority) + 1]++;
} else {
- if (ieee->seq_ctrl[0] == 0xFFF)
- ieee->seq_ctrl[0] = 0;
- else
- ieee->seq_ctrl[0]++;
+ if (ieee->seq_ctrl[0] == 0xFFF)
+ ieee->seq_ctrl[0] = 0;
+ else
+ ieee->seq_ctrl[0]++;
}
} else {
if (unlikely(skb->len < sizeof(struct rtl_80211_hdr_3addr))) {
@@ -826,7 +785,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC);
- if(!txb){
+ if (!txb) {
printk(KERN_WARNING "%s: Could not allocate TXB\n",
ieee->dev->name);
goto failed;
@@ -839,8 +798,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
success:
//WB add to fill data tcb_desc here. only first fragment is considered, need to change, and you may remove to other place.
- if (txb)
- {
+ if (txb) {
struct cb_desc *tcb_desc = (struct cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->bTxEnableFwCalcDur = 1;
if (is_multicast_ether_addr(header.addr1))
@@ -862,9 +820,9 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&ieee->lock, flags);
dev_kfree_skb_any(skb);
if (txb) {
- if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE){
+ if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) {
ieee80211_softmac_xmit(txb, ieee);
- }else{
+ } else {
if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
stats->tx_packets++;
stats->tx_bytes += __le16_to_cpu(txb->payload_size);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
index be08cd1d37a7..9dd5c04181ea 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
@@ -70,10 +70,10 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
}
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
- for(i=0; i<ARRAY_SIZE(ieee80211_modes); i++) {
+ for (i = 0; i < ARRAY_SIZE(ieee80211_modes); i++) {
if (network->mode & BIT(i)) {
- sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
- pname +=ieee80211_modes[i].mode_size;
+ sprintf(pname, ieee80211_modes[i].mode_string, ieee80211_modes[i].mode_size);
+ pname += ieee80211_modes[i].mode_size;
}
}
*pname = '\0';
@@ -130,8 +130,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
max_rate = rate;
}
- if (network->mode >= IEEE_N_24G)//add N rate here;
- {
+ if (network->mode >= IEEE_N_24G) /* add N rate here */ {
struct ht_capability_ele *ht_cap = NULL;
bool is40M = false, isShortGI = false;
u8 max_mcs = 0;
@@ -139,13 +138,13 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
ht_cap = (struct ht_capability_ele *)&network->bssht.bdHTCapBuf[4];
else
ht_cap = (struct ht_capability_ele *)&network->bssht.bdHTCapBuf[0];
- is40M = (ht_cap->ChlWidth)?1:0;
- isShortGI = (ht_cap->ChlWidth)?
- ((ht_cap->ShortGI40Mhz)?1:0):
- ((ht_cap->ShortGI20Mhz)?1:0);
+ is40M = (ht_cap->ChlWidth) ? 1 : 0;
+ isShortGI = (ht_cap->ChlWidth) ?
+ ((ht_cap->ShortGI40Mhz) ? 1 : 0) :
+ ((ht_cap->ShortGI20Mhz) ? 1 : 0);
max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL);
- rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f];
+ rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
if (rate > max_rate)
max_rate = rate;
}
@@ -178,7 +177,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
+ start = iwe_stream_add_point(info, start, stop, &iwe, custom);
if (ieee->wpa_enabled && network->wpa_ie_len) {
char buf[MAX_WPA_IE_LEN * 2 + 30];
@@ -219,7 +218,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
" Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
+ start = iwe_stream_add_point(info, start, stop, &iwe, custom);
return start;
}
@@ -243,7 +242,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
list_for_each_entry(network, &ieee->network_list, list) {
i++;
- if((stop-ev)<200) {
+ if ((stop - ev) < 200) {
err = -E2BIG;
break;
}
@@ -454,7 +453,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
IEEE80211_DEBUG_WX("GET_ENCODE\n");
- if(ieee->iw_mode == IW_MODE_MONITOR)
+ if (ieee->iw_mode == IW_MODE_MONITOR)
return -1;
key = erq->flags & IW_ENCODE_INDEX;
@@ -571,7 +570,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
ret = -EINVAL;
goto done;
}
- printk("alg name:%s\n",alg);
+ printk("alg name:%s\n", alg);
ops = try_then_request_module(ieee80211_get_crypto_ops(alg), module);
if (!ops) {
@@ -688,7 +687,7 @@ int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
ext->key_len = 0;
encoding->flags |= IW_ENCODE_DISABLED;
} else {
- if (strcmp(crypt->ops->name, "WEP") == 0 )
+ if (strcmp(crypt->ops->name, "WEP") == 0)
ext->alg = IW_ENCODE_ALG_WEP;
else if (strcmp(crypt->ops->name, "TKIP"))
ext->alg = IW_ENCODE_ALG_TKIP;
@@ -712,7 +711,7 @@ int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct iw_mlme *mlme = (struct iw_mlme *) extra;
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
case IW_MLME_DISASSOC:
@@ -765,7 +764,7 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
break;
case IW_AUTH_WPA_ENABLED:
- ieee->wpa_enabled = (data->value)?1:0;
+ ieee->wpa_enabled = (data->value) ? 1 : 0;
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
@@ -785,14 +784,14 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
{
u8 *buf;
- if (len>MAX_WPA_IE_LEN || (len && !ie)) {
- // printk("return error out, len:%d\n", len);
- return -EINVAL;
+ if (len > MAX_WPA_IE_LEN || (len && !ie)) {
+ //printk("return error out, len:%d\n", len);
+ return -EINVAL;
}
if (len) {
- if (len != ie[1]+2) {
+ if (len != ie[1] + 2) {
printk("len:%zu, ie:%d\n", len, ie[1]);
return -EINVAL;
}
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index 53869b3c985c..379a2ccf4d9f 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -162,7 +162,7 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, s
tag += 2;
}
- IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
+ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_BA, skb->data, skb->len);
return skb;
//return NULL;
}
@@ -229,7 +229,7 @@ static struct sk_buff *ieee80211_DELBA(
put_unaligned_le16(ReasonCode, tag);
tag += 2;
- IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
+ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_BA, skb->data, skb->len);
if (net_ratelimit())
IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA,
"<=====%s()\n", __func__);
@@ -331,9 +331,9 @@ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb)
return -1;
}
- IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
+ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_BA, skb->data, skb->len);
- req = (struct rtl_80211_hdr_3addr *) skb->data;
+ req = (struct rtl_80211_hdr_3addr *)skb->data;
tag = (u8 *)req;
dst = &req->addr2[0];
tag += sizeof(struct rtl_80211_hdr_3addr);
@@ -556,7 +556,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb)
return -1;
}
- IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
+ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_BA, skb->data, skb->len);
delba = (struct rtl_80211_hdr_3addr *)skb->data;
dst = &delba->addr2[0];
pDelBaParamSet = (union delba_param_set *)&delba->payload[2];
@@ -643,7 +643,7 @@ TsInitDelBA(struct ieee80211_device *ieee, struct ts_common_info *pTsCommonInfo,
ieee80211_send_DELBA(
ieee,
pTsCommonInfo->addr,
- (pTxTs->tx_admitted_ba_record.valid)?(&pTxTs->tx_admitted_ba_record):(&pTxTs->tx_pending_ba_record),
+ (pTxTs->tx_admitted_ba_record.valid) ? (&pTxTs->tx_admitted_ba_record) : (&pTxTs->tx_pending_ba_record),
TxRxSelect,
DELBA_REASON_END_BA);
} else if (TxRxSelect == RX_DIR) {
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
index b7769bca9740..79346a00af09 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
@@ -253,10 +253,10 @@ extern u8 MCS_FILTER_1SS[16];
/* 2007/07/12 MH We only define legacy and HT wireless mode now. */
#define LEGACY_WIRELESS_MODE IEEE_MODE_MASK
-#define CURRENT_RATE(WirelessMode, LegacyRate, HTRate) \
- ((WirelessMode & (LEGACY_WIRELESS_MODE)) != 0) ?\
- (LegacyRate) :\
- (PICK_RATE(LegacyRate, HTRate))
+#define CURRENT_RATE(WirelessMode, LegacyRate, HTRate) \
+ ((WirelessMode & (LEGACY_WIRELESS_MODE)) != 0) ? \
+ (LegacyRate) : \
+ (PICK_RATE(LegacyRate, HTRate))
// MCS Bw 40 {1~7, 12~15,32}
#define RATE_ADPT_1SS_MASK 0xFF
@@ -270,11 +270,10 @@ typedef enum _HT_AGGRE_SIZE {
HT_AGG_SIZE_16K = 1,
HT_AGG_SIZE_32K = 2,
HT_AGG_SIZE_64K = 3,
-}HT_AGGRE_SIZE_E, *PHT_AGGRE_SIZE_E;
+} HT_AGGRE_SIZE_E, *PHT_AGGRE_SIZE_E;
/* Indicate different AP vendor for IOT issue */
-typedef enum _HT_IOT_PEER
-{
+typedef enum _HT_IOT_PEER {
HT_IOT_PEER_UNKNOWN = 0,
HT_IOT_PEER_REALTEK = 1,
HT_IOT_PEER_BROADCOM = 2,
@@ -282,7 +281,7 @@ typedef enum _HT_IOT_PEER
HT_IOT_PEER_ATHEROS = 4,
HT_IOT_PEER_CISCO = 5,
HT_IOT_PEER_MAX = 6
-}HT_IOT_PEER_E, *PHTIOT_PEER_E;
+} HT_IOT_PEER_E, *PHTIOT_PEER_E;
/*
* IOT Action for different AP
@@ -298,6 +297,6 @@ typedef enum _HT_IOT_ACTION {
HT_IOT_ACT_CDD_FSYNC = 0x00000080,
HT_IOT_ACT_PURE_N_MODE = 0x00000100,
HT_IOT_ACT_FORCED_CTS2SELF = 0x00000200,
-}HT_IOT_ACTION_E, *PHT_IOT_ACTION_E;
+} HT_IOT_ACTION_E, *PHT_IOT_ACTION_E;
#endif //_RTL819XU_HTTYPE_H_
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
index c73a8058cf87..dba3f2db9f48 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
@@ -93,10 +93,6 @@ void HTUpdateDefaultSetting(struct ieee80211_device *ieee)
ieee->bTxDisableRateFallBack = 0;
ieee->bTxUseDriverAssingedRate = 0;
-#ifdef TO_DO_LIST
- // 8190 only. Assign duration operation mode to firmware
- pMgntInfo->bTxEnableFwCalcDur = (BOOLEAN)pNdisCommon->bRegTxEnableFwCalcDur;
-#endif
/*
* 8190 only, Realtek proprietary aggregation mode
* Set MPDUDensity=2, 1: Set MPDUDensity=2(32k) for Realtek AP and set MPDUDensity=0(8k) for others
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index 59d179ae7ad2..5cee1031a27c 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -105,7 +105,7 @@ static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
{
eth_zero_addr(pTsCommonInfo->addr);
memset(&pTsCommonInfo->t_spec, 0, sizeof(struct tspec_body));
- memset(&pTsCommonInfo->t_class, 0, sizeof(union qos_tclas)*TCLAS_NUM);
+ memset(&pTsCommonInfo->t_class, 0, sizeof(union qos_tclas) * TCLAS_NUM);
pTsCommonInfo->t_clas_proc = 0;
pTsCommonInfo->t_clas_num = 0;
}
@@ -180,14 +180,12 @@ void TSInitialize(struct ieee80211_device *ieee)
}
// Initialize unused Rx Reorder List.
INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
-//#ifdef TO_DO_LIST
for (count = 0; count < REORDER_ENTRY_NUM; count++) {
list_add_tail(&pRxReorderEntry->List, &ieee->RxReorder_Unused_List);
- if (count == (REORDER_ENTRY_NUM-1))
+ if (count == (REORDER_ENTRY_NUM - 1))
break;
- pRxReorderEntry = &ieee->RxReorderEntry[count+1];
+ pRxReorderEntry = &ieee->RxReorderEntry[count + 1];
}
-//#endif
}
static void AdmitTS(struct ieee80211_device *ieee,
@@ -259,7 +257,7 @@ static struct ts_common_info *SearchAdmitTRStream(struct ieee80211_device *ieee,
}
if (&pRet->list != psearch_list)
- return pRet ;
+ return pRet;
else
return NULL;
}
@@ -367,8 +365,8 @@ bool GetTs(
(&ieee->Rx_TS_Admit_List);
enum direction_value Dir = (ieee->iw_mode == IW_MODE_MASTER) ?
- ((TxRxSelect == TX_DIR)?DIR_DOWN:DIR_UP) :
- ((TxRxSelect == TX_DIR)?DIR_UP:DIR_DOWN);
+ ((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) :
+ ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN);
IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n");
if (!list_empty(pUnusedList)) {
(*ppTS) = list_entry(pUnusedList->next, struct ts_common_info, list);
@@ -417,7 +415,6 @@ static void RemoveTsEntry(struct ieee80211_device *ieee, struct ts_common_info *
TsInitDelBA(ieee, pTs, TxRxSelect);
if (TxRxSelect == RX_DIR) {
-//#ifdef TO_DO_LIST
struct rx_reorder_entry *pRxReorderEntry;
struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs;
if (timer_pending(&pRxTS->rx_pkt_pending_timer))
@@ -445,7 +442,6 @@ static void RemoveTsEntry(struct ieee80211_device *ieee, struct ts_common_info *
spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
}
-//#endif
} else {
struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
del_timer_sync(&pTxTS->ts_add_ba_timer);
@@ -530,7 +526,7 @@ void TsStartAddBaProcess(struct ieee80211_device *ieee, struct tx_ts_record *pTx
jiffies + msecs_to_jiffies(TS_ADDBA_DELAY));
} else {
IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Immediately Start ADDBA now!!\n", __func__);
- mod_timer(&pTxTS->ts_add_ba_timer, jiffies+10); //set 10 ticks
+ mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 10); //set 10 ticks
}
} else {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __func__);
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c
index de83daa0c9ed..2527cea60e3e 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.c
+++ b/drivers/staging/rtl8192u/r8180_93cx6.c
@@ -39,7 +39,6 @@ static void eprom_cs(struct net_device *dev, short bit)
udelay(EPROM_DELAY);
}
-
static void eprom_ck_cycle(struct net_device *dev)
{
u8 cmdreg;
@@ -58,7 +57,6 @@ static void eprom_ck_cycle(struct net_device *dev)
udelay(EPROM_DELAY);
}
-
static void eprom_w(struct net_device *dev, short bit)
{
u8 cmdreg;
@@ -76,7 +74,6 @@ static void eprom_w(struct net_device *dev, short bit)
udelay(EPROM_DELAY);
}
-
static short eprom_r(struct net_device *dev)
{
u8 bit;
@@ -94,7 +91,6 @@ static short eprom_r(struct net_device *dev)
return 0;
}
-
static void eprom_send_bits_string(struct net_device *dev, short b[], int len)
{
int i;
@@ -105,7 +101,6 @@ static void eprom_send_bits_string(struct net_device *dev, short b[], int len)
}
}
-
int eprom_read(struct net_device *dev, u32 addr)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -119,7 +114,7 @@ int eprom_read(struct net_device *dev, u32 addr)
ret = 0;
/* enable EPROM programming */
write_nic_byte_E(dev, EPROM_CMD,
- (EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT));
+ (EPROM_CMD_PROGRAM << EPROM_CMD_OPERATING_MODE_SHIFT));
force_pci_posting(dev);
udelay(EPROM_DELAY);
@@ -162,7 +157,7 @@ int eprom_read(struct net_device *dev, u32 addr)
if (err < 0)
return err;
- ret |= err<<(15-i);
+ ret |= err << (15 - i);
}
eprom_cs(dev, 0);
@@ -170,6 +165,6 @@ int eprom_read(struct net_device *dev, u32 addr)
/* disable EPROM programming */
write_nic_byte_E(dev, EPROM_CMD,
- (EPROM_CMD_NORMAL<<EPROM_CMD_OPERATING_MODE_SHIFT));
+ (EPROM_CMD_NORMAL << EPROM_CMD_OPERATING_MODE_SHIFT));
return ret;
}
diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.c b/drivers/staging/rtl8192u/r8190_rtl8256.c
index 92de92a3325a..b169460b9f26 100644
--- a/drivers/staging/rtl8192u/r8190_rtl8256.c
+++ b/drivers/staging/rtl8192u/r8190_rtl8256.c
@@ -42,9 +42,9 @@ void phy_set_rf8256_bandwidth(struct net_device *dev, enum ht_channel_width Band
switch (Bandwidth) {
case HT_CHANNEL_WIDTH_20:
- if (priv->card_8192_version == VERSION_819XU_A
- || priv->card_8192_version
- == VERSION_819XU_B) { /* 8256 D-cut, E-cut, xiong: consider it later! */
+ if (priv->card_8192_version == VERSION_819XU_A ||
+ priv->card_8192_version ==
+ VERSION_819XU_B) { /* 8256 D-cut, E-cut, xiong: consider it later! */
rtl8192_phy_SetRFReg(dev,
(enum rf90_radio_path_e)eRFPath,
0x0b, bMask12Bits, 0x100); /* phy para:1ba */
@@ -79,10 +79,10 @@ void phy_set_rf8256_bandwidth(struct net_device *dev, enum ht_channel_width Band
default:
RT_TRACE(COMP_ERR, "phy_set_rf8256_bandwidth(): unknown Bandwidth: %#X\n", Bandwidth);
break;
-
}
}
}
+
/*--------------------------------------------------------------------------
* Overview: Interface to config 8256
* Input: struct net_device* dev
@@ -101,6 +101,7 @@ void phy_rf8256_config(struct net_device *dev)
/* Config BB and RF */
phy_rf8256_config_para_file(dev);
}
+
/*--------------------------------------------------------------------------
* Overview: Interface to config 8256
* Input: struct net_device* dev
@@ -137,12 +138,12 @@ static void phy_rf8256_config_para_file(struct net_device *dev)
break;
case RF90_PATH_B:
case RF90_PATH_D:
- u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16);
+ u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV << 16);
break;
}
/*----Set RF_ENV enable----*/
- rtl8192_setBBreg(dev, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1);
+ rtl8192_setBBreg(dev, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
/*----Set RF_ENV output high----*/
rtl8192_setBBreg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
@@ -151,7 +152,7 @@ static void phy_rf8256_config_para_file(struct net_device *dev)
rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); /* Set 0 to 4 bits for Z-serial and set 1 to 6 bits for 8258 */
rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); /* Set 0 to 12 bits for Z-serial and 8258, and set 1 to 14 bits for ??? */
- rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path_e) eRFPath, 0x0, bMask12Bits, 0xbf);
+ rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path_e)eRFPath, 0x0, bMask12Bits, 0xbf);
/* Check RF block (for FPGA platform only)----
* TODO: this function should be removed on ASIC , Emily 2007.2.2
@@ -207,7 +208,7 @@ static void phy_rf8256_config_para_file(struct net_device *dev)
break;
case RF90_PATH_B:
case RF90_PATH_D:
- rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue);
+ rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV << 16, u4RegValue);
break;
}
@@ -215,7 +216,6 @@ static void phy_rf8256_config_para_file(struct net_device *dev)
RT_TRACE(COMP_ERR, "phy_rf8256_config_para_file():Radio[%d] Fail!!", eRFPath);
goto phy_RF8256_Config_ParaFile_Fail;
}
-
}
RT_TRACE(COMP_PHY, "PHY Initialization Success\n");
@@ -225,11 +225,11 @@ phy_RF8256_Config_ParaFile_Fail:
RT_TRACE(COMP_ERR, "PHY Initialization failed\n");
}
-
void phy_set_rf8256_cck_tx_power(struct net_device *dev, u8 powerlevel)
{
u32 TxAGC = 0;
struct r8192_priv *priv = ieee80211_priv(dev);
+
TxAGC = powerlevel;
if (priv->bDynamicTxLowPower) {
@@ -244,7 +244,6 @@ void phy_set_rf8256_cck_tx_power(struct net_device *dev, u8 powerlevel)
rtl8192_setBBreg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC);
}
-
void phy_set_rf8256_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -255,16 +254,16 @@ void phy_set_rf8256_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
u8 byte0, byte1, byte2, byte3;
powerBase0 = powerlevel + priv->TxPowerDiff; /* OFDM rates */
- powerBase0 = (powerBase0<<24) | (powerBase0<<16) | (powerBase0<<8) | powerBase0;
+ powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | (powerBase0 << 8) | powerBase0;
powerBase1 = powerlevel; /* MCS rates */
- powerBase1 = (powerBase1<<24) | (powerBase1<<16) | (powerBase1<<8) | powerBase1;
+ powerBase1 = (powerBase1 << 24) | (powerBase1 << 16) | (powerBase1 << 8) | powerBase1;
for (index = 0; index < 6; index++) {
- writeVal = priv->MCSTxPowerLevelOriginalOffset[index] + ((index < 2)?powerBase0:powerBase1);
+ writeVal = priv->MCSTxPowerLevelOriginalOffset[index] + ((index < 2) ? powerBase0 : powerBase1);
byte0 = (u8)(writeVal & 0x7f);
- byte1 = (u8)((writeVal & 0x7f00)>>8);
- byte2 = (u8)((writeVal & 0x7f0000)>>16);
- byte3 = (u8)((writeVal & 0x7f000000)>>24);
+ byte1 = (u8)((writeVal & 0x7f00) >> 8);
+ byte2 = (u8)((writeVal & 0x7f0000) >> 16);
+ byte3 = (u8)((writeVal & 0x7f000000) >> 24);
if (byte0 > 0x24)
/* Max power index = 0x24 */
@@ -278,7 +277,7 @@ void phy_set_rf8256_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
/* for tx power track */
if (index == 3) {
- writeVal_tmp = (byte3<<24) | (byte2<<16) | (byte1<<8) | byte0;
+ writeVal_tmp = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
priv->Pwr_Track = writeVal_tmp;
}
@@ -288,10 +287,9 @@ void phy_set_rf8256_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
*/
writeVal = 0x03030303;
} else {
- writeVal = (byte3<<24) | (byte2<<16) | (byte1<<8) | byte0;
- }
- rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal);
+ writeVal = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
+ }
+ rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal);
}
return;
-
}
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index fe1f279ca368..2821411878ce 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -2076,14 +2076,6 @@ static void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode)
wireless_mode = WIRELESS_MODE_B;
}
}
-#ifdef TO_DO_LIST
- /* TODO: this function doesn't work well at this time,
- * we should wait for FPGA
- */
- ActUpdateChannelAccessSetting(
- pAdapter, pHalData->CurrentWirelessMode,
- &pAdapter->MgntInfo.Info8185.ChannelAccessSetting);
-#endif
priv->ieee80211->mode = wireless_mode;
if (wireless_mode == WIRELESS_MODE_N_24G ||
@@ -2096,7 +2088,7 @@ static void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode)
}
/* init priv variables here. only non_zero value should be initialized here. */
-static void rtl8192_init_priv_variable(struct net_device *dev)
+static int rtl8192_init_priv_variable(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 i;
@@ -2159,12 +2151,6 @@ static void rtl8192_init_priv_variable(struct net_device *dev)
priv->ieee80211->InitialGainHandler = InitialGain819xUsb;
priv->card_type = USB;
-#ifdef TO_DO_LIST
- if (Adapter->bInHctTest) {
- pHalData->ShortRetryLimit = 7;
- pHalData->LongRetryLimit = 7;
- }
-#endif
priv->ShortRetryLimit = 0x30;
priv->LongRetryLimit = 0x30;
priv->EarlyRxThreshold = 7;
@@ -2180,34 +2166,6 @@ static void rtl8192_init_priv_variable(struct net_device *dev)
* TRUE: SW provides them
*/
(false ? TCR_SAT : 0);
-#ifdef TO_DO_LIST
- if (Adapter->bInHctTest)
- pHalData->ReceiveConfig =
- pHalData->CSMethod |
- /* accept management/data */
- RCR_AMF | RCR_ADF |
- /* accept control frame for SW
- * AP needs PS-poll
- */
- RCR_ACF |
- /* accept BC/MC/UC */
- RCR_AB | RCR_AM | RCR_APM |
- /* accept ICV/CRC error
- * packet
- */
- RCR_AICV | RCR_ACRC32 |
- /* Max DMA Burst Size per Tx
- * DMA Burst, 7: unlimited.
- */
- ((u32)7 << RCR_MXDMA_OFFSET) |
- /* Rx FIFO Threshold,
- * 7: No Rx threshold.
- */
- (pHalData->EarlyRxThreshold << RCR_FIFO_OFFSET) |
- (pHalData->EarlyRxThreshold == 7 ? RCR_OnlyErlPkt : 0);
- else
-
-#endif
priv->ReceiveConfig =
/* accept management/data */
RCR_AMF | RCR_ADF |
@@ -2223,6 +2181,8 @@ static void rtl8192_init_priv_variable(struct net_device *dev)
priv->AcmControl = 0;
priv->pFirmware = kzalloc(sizeof(rt_firmware), GFP_KERNEL);
+ if (!priv->pFirmware)
+ return -ENOMEM;
/* rx related queue */
skb_queue_head_init(&priv->rx_queue);
@@ -2236,6 +2196,8 @@ static void rtl8192_init_priv_variable(struct net_device *dev)
for (i = 0; i < MAX_QUEUE_SIZE; i++)
skb_queue_head_init(&priv->ieee80211->skb_drv_aggQ[i]);
priv->rf_set_chan = rtl8192_phy_SwChnl;
+
+ return 0;
}
/* init lock here */
@@ -2605,7 +2567,10 @@ static short rtl8192_init(struct net_device *dev)
memcpy(priv->txqueue_to_outpipemap, queuetopipe, 9);
}
#endif
- rtl8192_init_priv_variable(dev);
+ err = rtl8192_init_priv_variable(dev);
+ if (err)
+ return err;
+
rtl8192_init_priv_lock(priv);
rtl8192_init_priv_task(dev);
rtl8192_get_eeprom_size(dev);
@@ -2658,19 +2623,10 @@ static void rtl8192_hwconfig(struct net_device *dev)
regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
break;
case WIRELESS_MODE_AUTO:
-#ifdef TO_DO_LIST
- if (Adapter->bInHctTest) {
- regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
- regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
- } else
-#endif
- {
- regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
- RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
- regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
- }
+ regBwOpMode = BW_OPMODE_20MHZ;
+ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
+ RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
+ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
break;
case WIRELESS_MODE_N_24G:
/* It support CCK rate by default. CCK rate will be filtered
@@ -2841,48 +2797,6 @@ static bool rtl8192_adapter_start(struct net_device *dev)
}
RT_TRACE(COMP_INIT, "%s():after firmware download\n", __func__);
-#ifdef TO_DO_LIST
- if (Adapter->ResetProgress == RESET_TYPE_NORESET) {
- if (pMgntInfo->RegRfOff) { /* User disable RF via registry. */
- RT_TRACE((COMP_INIT | COMP_RF), DBG_LOUD,
- ("InitializeAdapter819xUsb(): Turn off RF for RegRfOff ----------\n"));
- MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_SW);
- /* Those actions will be discard in MgntActSet_RF_State
- * because of the same state
- */
- for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++)
- PHY_SetRFReg(Adapter,
- (enum rf90_radio_path_e)eRFPath,
- 0x4, 0xC00, 0x0);
- } else if (pMgntInfo->RfOffReason > RF_CHANGE_BY_PS) {
- /* H/W or S/W RF OFF before sleep. */
- RT_TRACE((COMP_INIT | COMP_RF), DBG_LOUD,
- ("InitializeAdapter819xUsb(): Turn off RF for RfOffReason(%d) ----------\n",
- pMgntInfo->RfOffReason));
- MgntActSet_RF_State(Adapter,
- eRfOff,
- pMgntInfo->RfOffReason);
- } else {
- pHalData->eRFPowerState = eRfOn;
- pMgntInfo->RfOffReason = 0;
- RT_TRACE((COMP_INIT | COMP_RF), DBG_LOUD,
- ("InitializeAdapter819xUsb(): RF is on ----------\n"));
- }
- } else {
- if (pHalData->eRFPowerState == eRfOff) {
- MgntActSet_RF_State(Adapter,
- eRfOff,
- pMgntInfo->RfOffReason);
- /* Those actions will be discard in MgntActSet_RF_State
- * because of the same state
- */
- for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++)
- PHY_SetRFReg(Adapter,
- (enum rf90_radio_path_e)eRFPath,
- 0x4, 0xC00, 0x0);
- }
- }
-#endif
/* config RF. */
if (priv->ResetProgress == RESET_TYPE_NORESET) {
rtl8192_phy_RFConfig(dev);
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index ade14ef05730..c23e43b095d9 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -1334,7 +1334,7 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev)
return;
}
/*DbgPrint("Schedule TxPowerTrackingWorkItem\n");*/
- queue_delayed_work(priv->priv_wq, &priv->txpower_tracking_wq, 0);
+ queue_delayed_work(priv->priv_wq, &priv->txpower_tracking_wq, 0);
TM_Trigger = 0;
}
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c
index 153d4ee0ec07..dd81d210bd49 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware.c
@@ -231,7 +231,7 @@ bool init_firmware(struct net_device *dev)
rst_opt = OPT_FIRMWARE_RESET;
starting_state = FW_INIT_STEP2_DATA;
} else {
- RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n");
+ RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n");
}
/*
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index 5f04afe53d69..c04d8eca0cfb 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -516,16 +516,6 @@ static void rtl8192_phyConfigBB(struct net_device *dev,
{
u32 i;
-#ifdef TO_DO_LIST
- u32 *rtl8192PhyRegArrayTable = NULL, *rtl8192AgcTabArrayTable = NULL;
-
- if (Adapter->bInHctTest) {
- PHY_REGArrayLen = PHY_REGArrayLengthDTM;
- AGCTAB_ArrayLen = AGCTAB_ArrayLengthDTM;
- Rtl8190PHY_REGArray_Table = Rtl819XPHY_REGArrayDTM;
- Rtl8190AGCTAB_Array_Table = Rtl819XAGCTAB_ArrayDTM;
- }
-#endif
if (ConfigType == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < PHY_REG_1T2RArrayLength; i += 2) {
rtl8192_setBBreg(dev, Rtl8192UsbPHY_REG_1T2RArray[i],
@@ -1059,10 +1049,6 @@ static void rtl8192_SetTxPowerLevel(struct net_device *dev, u8 channel)
switch (priv->rf_chip) {
case RF_8225:
-#ifdef TO_DO_LIST
- PHY_SetRF8225CckTxPower(Adapter, powerlevel);
- PHY_SetRF8225OfdmTxPower(Adapter, powerlevelOFDM24G);
-#endif
break;
case RF_8256:
@@ -1160,48 +1146,6 @@ bool rtl8192_SetRFPowerState(struct net_device *dev,
RT_TRACE(COMP_ERR, "Not support rf_chip(%x)\n", priv->rf_chip);
break;
}
-#ifdef TO_DO_LIST
- if (bResult) {
- /* Update current RF state variable. */
- pHalData->eRFPowerState = eRFPowerState;
- switch (pHalData->RFChipID) {
- case RF_8256:
- switch (pHalData->eRFPowerState) {
- case eRfOff:
- /* If Rf off reason is from IPS,
- * LED should blink with no link
- */
- if (pMgntInfo->RfOffReason == RF_CHANGE_BY_IPS)
- Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_NO_LINK);
- else
- /* Turn off LED if RF is not ON. */
- Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_POWER_OFF);
- break;
-
- case eRfOn:
- /* Turn on RF we are still linked, which might
- * happen when we quickly turn off and on HW RF.
- */
- if (pMgntInfo->bMediaConnect)
- Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_LINK);
- else
- /* Turn off LED if RF is not ON. */
- Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_NO_LINK);
- break;
-
- default:
- break;
- }
- break;
-
- default:
- RT_TRACE(COMP_RF, DBG_LOUD, "%s(): Unknown RF type\n",
- __func__);
- break;
- }
-
- }
-#endif
priv->SetRFPowerStateInProgress = false;
return bResult;
@@ -1628,9 +1572,6 @@ void rtl8192_SetBWModeWorkItem(struct net_device *dev)
/* <3> Set RF related register */
switch (priv->rf_chip) {
case RF_8225:
-#ifdef TO_DO_LIST
- PHY_SetRF8225Bandwidth(Adapter, pHalData->CurrentChannelBW);
-#endif
break;
case RF_8256:
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index b554cf8bd679..0c3ae8495afb 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -258,7 +258,7 @@ void r8712_stop_drv_timers(struct _adapter *padapter)
del_timer_sync(&padapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer);
}
-static u8 init_default_value(struct _adapter *padapter)
+static void init_default_value(struct _adapter *padapter)
{
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
@@ -292,37 +292,41 @@ static u8 init_default_value(struct _adapter *padapter)
r8712_init_registrypriv_dev_network(padapter);
r8712_update_registrypriv_dev_network(padapter);
/*misc.*/
- return _SUCCESS;
}
-u8 r8712_init_drv_sw(struct _adapter *padapter)
+int r8712_init_drv_sw(struct _adapter *padapter)
{
- if (r8712_init_cmd_priv(&padapter->cmdpriv))
- return _FAIL;
+ int ret;
+
+ ret = r8712_init_cmd_priv(&padapter->cmdpriv);
+ if (ret)
+ return ret;
padapter->cmdpriv.padapter = padapter;
- if (r8712_init_evt_priv(&padapter->evtpriv))
- return _FAIL;
- if (r8712_init_mlme_priv(padapter) == _FAIL)
- return _FAIL;
+ ret = r8712_init_evt_priv(&padapter->evtpriv);
+ if (ret)
+ return ret;
+ ret = r8712_init_mlme_priv(padapter);
+ if (ret)
+ return ret;
_r8712_init_xmit_priv(&padapter->xmitpriv, padapter);
_r8712_init_recv_priv(&padapter->recvpriv, padapter);
memset((unsigned char *)&padapter->securitypriv, 0,
sizeof(struct security_priv));
timer_setup(&padapter->securitypriv.tkip_timer,
r8712_use_tkipkey_handler, 0);
- if (_r8712_init_sta_priv(&padapter->stapriv))
- return _FAIL;
+ ret = _r8712_init_sta_priv(&padapter->stapriv);
+ if (ret)
+ return ret;
padapter->stapriv.padapter = padapter;
r8712_init_bcmc_stainfo(padapter);
r8712_init_pwrctrl_priv(padapter);
mp871xinit(padapter);
- if (init_default_value(padapter) != _SUCCESS)
- return _FAIL;
+ init_default_value(padapter);
r8712_InitSwLeds(padapter);
- return _SUCCESS;
+ return ret;
}
-u8 r8712_free_drv_sw(struct _adapter *padapter)
+void r8712_free_drv_sw(struct _adapter *padapter)
{
struct net_device *pnetdev = padapter->pnetdev;
@@ -337,7 +341,6 @@ u8 r8712_free_drv_sw(struct _adapter *padapter)
mp871xdeinit(padapter);
if (pnetdev)
free_netdev(pnetdev);
- return _SUCCESS;
}
static void enable_video_mode(struct _adapter *padapter, int cbw40_value)
diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c
index 84c4c8580f9a..215fca4abb3a 100644
--- a/drivers/staging/rtl8712/recv_linux.c
+++ b/drivers/staging/rtl8712/recv_linux.c
@@ -29,24 +29,23 @@
/*init os related resource in struct recv_priv*/
/*alloc os related resource in union recv_frame*/
-int r8712_os_recv_resource_alloc(struct _adapter *padapter,
- union recv_frame *precvframe)
+void r8712_os_recv_resource_alloc(struct _adapter *padapter,
+ union recv_frame *precvframe)
{
precvframe->u.hdr.pkt_newalloc = NULL;
precvframe->u.hdr.pkt = NULL;
- return _SUCCESS;
}
/*alloc os related resource in struct recv_buf*/
int r8712_os_recvbuf_resource_alloc(struct _adapter *padapter,
struct recv_buf *precvbuf)
{
- int res = _SUCCESS;
+ int res = 0;
precvbuf->irp_pending = false;
precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
if (!precvbuf->purb)
- res = _FAIL;
+ res = -ENOMEM;
precvbuf->pskb = NULL;
precvbuf->pallocated_buf = NULL;
precvbuf->pbuf = NULL;
@@ -60,8 +59,8 @@ int r8712_os_recvbuf_resource_alloc(struct _adapter *padapter,
}
/*free os related resource in struct recv_buf*/
-int r8712_os_recvbuf_resource_free(struct _adapter *padapter,
- struct recv_buf *precvbuf)
+void r8712_os_recvbuf_resource_free(struct _adapter *padapter,
+ struct recv_buf *precvbuf)
{
if (precvbuf->pskb)
dev_kfree_skb_any(precvbuf->pskb);
@@ -69,7 +68,6 @@ int r8712_os_recvbuf_resource_free(struct _adapter *padapter,
usb_kill_urb(precvbuf->purb);
usb_free_urb(precvbuf->purb);
}
- return _SUCCESS;
}
void r8712_handle_tkip_mic_err(struct _adapter *adapter, u8 bgroup)
@@ -115,8 +113,8 @@ void r8712_recv_indicatepkt(struct _adapter *adapter,
skb->protocol = eth_type_trans(skb, adapter->pnetdev);
netif_rx(skb);
recvframe->u.hdr.pkt = NULL; /* pointers to NULL before
- * r8712_free_recvframe()
- */
+ * r8712_free_recvframe()
+ */
r8712_free_recvframe(recvframe, free_recv_queue);
return;
_recv_indicatepkt_drop:
diff --git a/drivers/staging/rtl8712/recv_osdep.h b/drivers/staging/rtl8712/recv_osdep.h
index dcd3b484c793..d8c1fa74f544 100644
--- a/drivers/staging/rtl8712/recv_osdep.h
+++ b/drivers/staging/rtl8712/recv_osdep.h
@@ -18,22 +18,22 @@
#include "drv_types.h"
#include <linux/skbuff.h>
-sint _r8712_init_recv_priv(struct recv_priv *precvpriv,
+void _r8712_init_recv_priv(struct recv_priv *precvpriv,
struct _adapter *padapter);
void _r8712_free_recv_priv(struct recv_priv *precvpriv);
-s32 r8712_recv_entry(union recv_frame *precv_frame);
+void r8712_recv_entry(union recv_frame *precv_frame);
void r8712_recv_indicatepkt(struct _adapter *adapter,
union recv_frame *precv_frame);
void r8712_handle_tkip_mic_err(struct _adapter *padapter, u8 bgroup);
-int r8712_init_recv_priv(struct recv_priv *precvpriv,
- struct _adapter *padapter);
+void r8712_init_recv_priv(struct recv_priv *precvpriv,
+ struct _adapter *padapter);
void r8712_free_recv_priv(struct recv_priv *precvpriv);
-int r8712_os_recv_resource_alloc(struct _adapter *padapter,
- union recv_frame *precvframe);
+void r8712_os_recv_resource_alloc(struct _adapter *padapter,
+ union recv_frame *precvframe);
int r8712_os_recvbuf_resource_alloc(struct _adapter *padapter,
struct recv_buf *precvbuf);
-int r8712_os_recvbuf_resource_free(struct _adapter *padapter,
- struct recv_buf *precvbuf);
+void r8712_os_recvbuf_resource_free(struct _adapter *padapter,
+ struct recv_buf *precvbuf);
void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl);
#endif
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c
index 6a72a4ad176a..ff3cb09c57a6 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.c
+++ b/drivers/staging/rtl8712/rtl8712_cmd.c
@@ -263,11 +263,6 @@ static struct cmd_obj *cmd_hdl_filter(struct _adapter *padapter,
return pcmd_r; /* if returning pcmd_r == NULL, pcmd must be free. */
}
-static u8 check_cmd_fifo(struct _adapter *padapter, uint sz)
-{
- return _SUCCESS;
-}
-
u8 r8712_fw_cmd(struct _adapter *pAdapter, u32 cmd)
{
int pollingcnts = 50;
@@ -311,7 +306,7 @@ int r8712_cmd_thread(void *context)
break;
if (padapter->driver_stopped || padapter->surprise_removed)
break;
- if (r8712_register_cmd_alive(padapter) != _SUCCESS)
+ if (r8712_register_cmd_alive(padapter))
continue;
_next:
pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue);
@@ -359,13 +354,6 @@ _next:
(pcmdpriv->cmd_seq << 24));
pcmdbuf += 2; /* 8 bytes alignment */
memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
- while (check_cmd_fifo(padapter, wr_sz) == _FAIL) {
- if (padapter->driver_stopped ||
- padapter->surprise_removed)
- break;
- msleep(100);
- continue;
- }
if (blnPending)
wr_sz += 8; /* Append 8 bytes */
r8712_write_mem(padapter, RTL8712_DMA_H2CCMD, wr_sz,
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index 82ddc0c3ecd4..9901815604f4 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -35,11 +35,11 @@ static u8 rfc1042_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
static void recv_tasklet(void *priv);
-int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter)
+void r8712_init_recv_priv(struct recv_priv *precvpriv,
+ struct _adapter *padapter)
{
int i;
struct recv_buf *precvbuf;
- int res = _SUCCESS;
addr_t tmpaddr = 0;
int alignment = 0;
struct sk_buff *pskb = NULL;
@@ -49,15 +49,14 @@ int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter)
precvpriv->pallocated_recv_buf =
kzalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4, GFP_ATOMIC);
if (!precvpriv->pallocated_recv_buf)
- return _FAIL;
+ return;
precvpriv->precv_buf = precvpriv->pallocated_recv_buf + 4 -
((addr_t)(precvpriv->pallocated_recv_buf) & 3);
precvbuf = (struct recv_buf *)precvpriv->precv_buf;
for (i = 0; i < NR_RECVBUFF; i++) {
INIT_LIST_HEAD(&precvbuf->list);
spin_lock_init(&precvbuf->recvbuf_lock);
- res = r8712_os_recvbuf_resource_alloc(padapter, precvbuf);
- if (res == _FAIL)
+ if (r8712_os_recvbuf_resource_alloc(padapter, precvbuf))
break;
precvbuf->ref_cnt = 0;
precvbuf->adapter = padapter;
@@ -83,7 +82,6 @@ int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter)
}
pskb = NULL;
}
- return res;
}
void r8712_free_recv_priv(struct recv_priv *precvpriv)
@@ -107,7 +105,7 @@ void r8712_free_recv_priv(struct recv_priv *precvpriv)
skb_queue_len(&precvpriv->free_recv_skb_queue));
}
-int r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf)
+void r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf)
{
precvbuf->transfer_len = 0;
precvbuf->len = 0;
@@ -118,10 +116,9 @@ int r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf)
precvbuf->ptail = precvbuf->pbuf;
precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ;
}
- return _SUCCESS;
}
-int r8712_free_recvframe(union recv_frame *precvframe,
+void r8712_free_recvframe(union recv_frame *precvframe,
struct __queue *pfree_recv_queue)
{
unsigned long irqL;
@@ -140,7 +137,6 @@ int r8712_free_recvframe(union recv_frame *precvframe,
precvpriv->free_recvframe_cnt++;
}
spin_unlock_irqrestore(&pfree_recv_queue->lock, irqL);
- return _SUCCESS;
}
static void update_recvframe_attrib_from_recvstat(struct rx_pkt_attrib *pattrib,
@@ -323,7 +319,7 @@ union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *padapter,
return prtnframe;
}
-static int amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe)
+static void amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe)
{
int a_len, padding_len;
u16 eth_type, nSubframe_Length;
@@ -421,7 +417,6 @@ static int amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe)
exit:
prframe->u.hdr.len = 0;
r8712_free_recvframe(prframe, pfree_recv_queue);
- return _SUCCESS;
}
void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf)
@@ -511,7 +506,6 @@ int r8712_recv_indicatepkts_in_order(struct _adapter *padapter,
union recv_frame *prframe;
struct rx_pkt_attrib *pattrib;
int bPktInBuf = false;
- struct recv_priv *precvpriv = &padapter->recvpriv;
struct __queue *ppending_recvframe_queue =
&preorder_ctrl->pending_recvframe_queue;
@@ -548,10 +542,7 @@ int r8712_recv_indicatepkts_in_order(struct _adapter *padapter,
prframe);
}
} else if (pattrib->amsdu == 1) {
- if (amsdu_to_msdu(padapter, prframe) !=
- _SUCCESS)
- r8712_free_recvframe(prframe,
- &precvpriv->free_recv_queue);
+ amsdu_to_msdu(padapter, prframe);
}
/* Update local variables. */
bPktInBuf = false;
@@ -579,9 +570,9 @@ static int recv_indicatepkt_reorder(struct _adapter *padapter,
if (!padapter->driver_stopped &&
!padapter->surprise_removed) {
r8712_recv_indicatepkt(padapter, prframe);
- return _SUCCESS;
+ return 0;
} else {
- return _FAIL;
+ return -EINVAL;
}
}
}
@@ -603,8 +594,7 @@ static int recv_indicatepkt_reorder(struct _adapter *padapter,
* 2. All packets with SeqNum larger than or equal to
* WinStart => Buffer it.
*/
- if (r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, false) ==
- true) {
+ if (r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, false)) {
mod_timer(&preorder_ctrl->reordering_ctrl_timer,
jiffies + msecs_to_jiffies(REORDER_WAIT_TIME));
spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
@@ -612,10 +602,10 @@ static int recv_indicatepkt_reorder(struct _adapter *padapter,
spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
del_timer(&preorder_ctrl->reordering_ctrl_timer);
}
- return _SUCCESS;
+ return 0;
_err_exit:
spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
- return _FAIL;
+ return -ENOMEM;
}
void r8712_reordering_ctrl_timeout_handler(void *pcontext)
@@ -641,7 +631,7 @@ static int r8712_process_recv_indicatepkts(struct _adapter *padapter,
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
if (phtpriv->ht_option == 1) { /*B/G/N Mode*/
- if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) {
+ if (recv_indicatepkt_reorder(padapter, prframe)) {
/* including perform A-MPDU Rx Ordering Buffer Control*/
if (!padapter->driver_stopped &&
!padapter->surprise_removed)
@@ -649,8 +639,8 @@ static int r8712_process_recv_indicatepkts(struct _adapter *padapter,
}
} else { /*B/G mode*/
retval = r8712_wlanhdr_to_ethhdr(prframe);
- if (retval != _SUCCESS)
- return retval;
+ if (retval)
+ return _FAIL;
if (!padapter->driver_stopped && !padapter->surprise_removed) {
/* indicate this recv_frame */
r8712_recv_indicatepkt(padapter, prframe);
@@ -991,7 +981,7 @@ _exit_recv_func:
return retval;
}
-static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
+static void recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
{
u8 *pbuf, shift_sz = 0;
u8 frag, mf;
@@ -1018,7 +1008,7 @@ static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
/* In this case, it means the MAX_RECVBUF_SZ is too small to
* get the data from 8712u.
*/
- return _FAIL;
+ return;
}
do {
prxstat = (struct recv_stat *)pbuf;
@@ -1031,13 +1021,13 @@ static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16;
drvinfo_sz <<= 3;
if (pkt_len <= 0)
- goto _exit_recvbuf2recvframe;
+ return;
/* Qos data, wireless lan header length is 26 */
if ((le32_to_cpu(prxstat->rxdw0) >> 23) & 0x01)
shift_sz = 2;
precvframe = r8712_alloc_recvframe(pfree_recv_queue);
if (!precvframe)
- goto _exit_recvbuf2recvframe;
+ return;
INIT_LIST_HEAD(&precvframe->u.hdr.list);
precvframe->u.hdr.precvbuf = NULL; /*can't access the precvbuf*/
precvframe->u.hdr.len = 0;
@@ -1068,7 +1058,7 @@ static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
} else {
precvframe->u.hdr.pkt = skb_clone(pskb, GFP_ATOMIC);
if (!precvframe->u.hdr.pkt)
- return _FAIL;
+ return;
precvframe->u.hdr.rx_head = pbuf;
precvframe->u.hdr.rx_data = pbuf;
precvframe->u.hdr.rx_tail = pbuf;
@@ -1088,8 +1078,6 @@ static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
precvframe = NULL;
pkt_copy = NULL;
} while ((transfer_len > 0) && pkt_cnt > 0);
-_exit_recvbuf2recvframe:
- return _SUCCESS;
}
static void recv_tasklet(void *priv)
diff --git a/drivers/staging/rtl8712/rtl8712_recv.h b/drivers/staging/rtl8712/rtl8712_recv.h
index 6954c5bfbcaf..3e385b2242d8 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.h
+++ b/drivers/staging/rtl8712/rtl8712_recv.h
@@ -136,7 +136,7 @@ union recv_frame {
} u;
};
-int r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf);
+void r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf);
void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf);
s32 r8712_signal_scale_mapping(s32 cur_sig);
void r8712_reordering_ctrl_timeout_handler(void *pcontext);
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 307b0e292976..c247f92207f5 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -246,7 +246,7 @@ void r8712_do_queue_select(struct _adapter *padapter,
}
#ifdef CONFIG_R8712_TX_AGGR
-u8 r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf)
+void r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf)
{
struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf;
@@ -260,11 +260,9 @@ u8 r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf)
/* dw1 */
ptx_desc->txdw1 |= cpu_to_le32((0x13 << QSEL_SHT) & 0x00001f00);
-
- return _SUCCESS;
}
-u8 r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf)
+void r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf)
{
struct xmit_frame *pxmitframe = (struct xmit_frame *)
pxmitbuf->priv_data;
@@ -278,12 +276,10 @@ u8 r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf)
pcmd_hdr->cmd_dw0 = cpu_to_le32((GEN_CMD_CODE(_AMSDU_TO_AMPDU) << 16) |
(pcmdpriv->cmd_seq << 24));
pcmdpriv->cmd_seq++;
-
- return _SUCCESS;
}
-u8 r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf,
- struct xmit_frame *pxmitframe)
+void r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf,
+ struct xmit_frame *pxmitframe)
{
struct _adapter *padapter = pxmitframe->padapter;
struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf;
@@ -319,13 +315,11 @@ u8 r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf,
((ptx_desc->txdw0 & 0x0000ffff) +
((TXDESC_SIZE + last_txcmdsz + padding_sz) &
0x0000ffff)));
-
- return _SUCCESS;
}
-u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf,
- struct xmit_frame *pxmitframe)
+void r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf,
+ struct xmit_frame *pxmitframe)
{
/* linux complete context doesn't need to protect */
pxmitframe->pxmitbuf = pxmitbuf;
@@ -336,10 +330,8 @@ u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf,
/*RTL8712_DMA_H2CCMD */
r8712_construct_txaggr_cmd_desc(pxmitbuf);
r8712_construct_txaggr_cmd_hdr(pxmitbuf);
- if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS)
- pxmitbuf->aggr_nr = 1;
-
- return _SUCCESS;
+ r8712_append_mpdu_unit(pxmitbuf, pxmitframe);
+ pxmitbuf->aggr_nr = 1;
}
u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf,
@@ -351,18 +343,17 @@ u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf,
/* buffer addr assoc */
pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE +
(((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff);
- if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) {
- r8712_free_xmitframe_ex(&pxmitframe->padapter->xmitpriv,
- pxmitframe);
- pxmitbuf->aggr_nr++;
- }
+ r8712_append_mpdu_unit(pxmitbuf, pxmitframe);
+ r8712_free_xmitframe_ex(&pxmitframe->padapter->xmitpriv,
+ pxmitframe);
+ pxmitbuf->aggr_nr++;
return TXDESC_SIZE +
(((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff);
}
-u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf,
- struct xmit_frame *pxmitframe)
+void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf,
+ struct xmit_frame *pxmitframe)
{
struct _adapter *padapter = pxmitframe->padapter;
struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
@@ -399,8 +390,6 @@ u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf,
}
r8712_write_port(pxmitframe->padapter, RTL8712_DMA_H2CCMD,
total_length + TXDESC_SIZE, (u8 *)pxmitframe);
-
- return _SUCCESS;
}
#endif
@@ -737,20 +726,19 @@ static void dump_xframe(struct _adapter *padapter,
}
}
-int r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe)
+void r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe)
{
- int res = _SUCCESS;
+ int res;
res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
pxmitframe->pkt = NULL;
if (res == _SUCCESS)
dump_xframe(padapter, pxmitframe);
- return res;
}
int r8712_xmit_enqueue(struct _adapter *padapter, struct xmit_frame *pxmitframe)
{
- if (r8712_xmit_classifier(padapter, pxmitframe) == _FAIL) {
+ if (r8712_xmit_classifier(padapter, pxmitframe)) {
pxmitframe->pkt = NULL;
return _FAIL;
}
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.h b/drivers/staging/rtl8712/rtl8712_xmit.h
index 9be8fb70c92e..0b56bd3ac4d0 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.h
+++ b/drivers/staging/rtl8712/rtl8712_xmit.h
@@ -102,10 +102,10 @@ void r8712_do_queue_select(struct _adapter *padapter,
struct pkt_attrib *pattrib);
#ifdef CONFIG_R8712_TX_AGGR
-u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf,
- struct xmit_frame *pxmitframe);
-u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf,
- struct xmit_frame *pxmitframe);
+void r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf,
+ struct xmit_frame *pxmitframe);
+void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf,
+ struct xmit_frame *pxmitframe);
#endif
#endif
diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h
index 28941423b7ed..c20dd5a6bbd1 100644
--- a/drivers/staging/rtl8712/rtl871x_io.h
+++ b/drivers/staging/rtl8712/rtl871x_io.h
@@ -11,8 +11,8 @@
* Larry Finger <Larry.Finger@lwfinger.net>
*
******************************************************************************/
-#ifndef _IO_H_
-#define _IO_H_
+#ifndef _RTL871X_IO_H_
+#define _RTL871X_IO_H_
#include "osdep_service.h"
#include "osdep_intf.h"
@@ -234,5 +234,4 @@ void r8712_write_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
uint r8712_alloc_io_queue(struct _adapter *adapter);
void r8712_free_io_queue(struct _adapter *adapter);
-#endif /*_RTL8711_IO_H_*/
-
+#endif /*_RTL871X_IO_H_*/
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index b08b9a191a34..944336e0d2e2 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -419,8 +419,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
pwep->KeyIndex |= 0x80000000;
memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
if (param->u.crypt.set_tx) {
- if (r8712_set_802_11_add_wep(padapter, pwep) ==
- (u8)_FAIL)
+ if (r8712_set_802_11_add_wep(padapter, pwep))
ret = -EOPNOTSUPP;
} else {
/* don't update "psecuritypriv->PrivacyAlgrthm" and
@@ -1585,7 +1584,7 @@ static int r8711_wx_set_enc(struct net_device *dev,
}
wep.KeyIndex |= 0x80000000; /* transmit key */
memcpy(wep.KeyMaterial, keybuf, wep.KeyLength);
- if (r8712_set_802_11_add_wep(padapter, &wep) == _FAIL)
+ if (r8712_set_802_11_add_wep(padapter, &wep))
return -EOPNOTSUPP;
return 0;
}
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
index f3c0a9348f56..6cdc6f1a6bc6 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
@@ -320,22 +320,22 @@ u8 r8712_set_802_11_authentication_mode(struct _adapter *padapter,
psecuritypriv->ndisauthtype = authmode;
if (psecuritypriv->ndisauthtype > 3)
psecuritypriv->AuthAlgrthm = 2; /* 802.1x */
- if (r8712_set_auth(padapter, psecuritypriv) == _SUCCESS)
- ret = true;
- else
+ if (r8712_set_auth(padapter, psecuritypriv))
ret = false;
+ else
+ ret = true;
return ret;
}
-u8 r8712_set_802_11_add_wep(struct _adapter *padapter,
- struct NDIS_802_11_WEP *wep)
+int r8712_set_802_11_add_wep(struct _adapter *padapter,
+ struct NDIS_802_11_WEP *wep)
{
sint keyid;
struct security_priv *psecuritypriv = &padapter->securitypriv;
keyid = wep->KeyIndex & 0x3fffffff;
if (keyid >= WEP_KEYS)
- return false;
+ return -EINVAL;
switch (wep->KeyLength) {
case 5:
psecuritypriv->PrivacyAlgrthm = _WEP40_;
@@ -351,7 +351,5 @@ u8 r8712_set_802_11_add_wep(struct _adapter *padapter,
wep->KeyLength);
psecuritypriv->DefKeylen[keyid] = wep->KeyLength;
psecuritypriv->PrivacyKeyIndex = keyid;
- if (r8712_set_key(padapter, psecuritypriv, keyid) == _FAIL)
- return false;
- return _SUCCESS;
+ return r8712_set_key(padapter, psecuritypriv, keyid);
}
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.h b/drivers/staging/rtl8712/rtl871x_ioctl_set.h
index 8b1085aea962..e2de820f61d9 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.h
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.h
@@ -28,8 +28,8 @@ u8 r8712_set_802_11_authentication_mode(struct _adapter *pdapter,
u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid);
-u8 r8712_set_802_11_add_wep(struct _adapter *padapter,
- struct NDIS_802_11_WEP *wep);
+int r8712_set_802_11_add_wep(struct _adapter *padapter,
+ struct NDIS_802_11_WEP *wep);
u8 r8712_set_802_11_disassociate(struct _adapter *padapter);
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index 0cc879a4d43f..cabdb3549a5a 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -53,7 +53,7 @@ int r8712_init_mlme_priv(struct _adapter *padapter)
pbuf = kmalloc_array(MAX_BSS_CNT, sizeof(struct wlan_network),
GFP_ATOMIC);
if (!pbuf)
- return _FAIL;
+ return -ENOMEM;
pmlmepriv->free_bss_buf = pbuf;
pnetwork = (struct wlan_network *)pbuf;
for (i = 0; i < MAX_BSS_CNT; i++) {
@@ -67,7 +67,7 @@ int r8712_init_mlme_priv(struct _adapter *padapter)
pmlmepriv->sitesurveyctrl.traffic_busy = false;
/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
r8712_init_mlme_timer(padapter);
- return _SUCCESS;
+ return 0;
}
struct wlan_network *_r8712_alloc_network(struct mlme_priv *pmlmepriv)
@@ -1144,8 +1144,8 @@ ask_for_joinbss:
return r8712_joinbss_cmd(adapter, pnetwork);
}
-sint r8712_set_auth(struct _adapter *adapter,
- struct security_priv *psecuritypriv)
+int r8712_set_auth(struct _adapter *adapter,
+ struct security_priv *psecuritypriv)
{
struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
struct cmd_obj *pcmd;
@@ -1153,12 +1153,12 @@ sint r8712_set_auth(struct _adapter *adapter,
pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
if (!pcmd)
- return _FAIL;
+ return -ENOMEM;
psetauthparm = kzalloc(sizeof(*psetauthparm), GFP_ATOMIC);
if (!psetauthparm) {
kfree(pcmd);
- return _FAIL;
+ return -ENOMEM;
}
psetauthparm->mode = (u8)psecuritypriv->AuthAlgrthm;
pcmd->cmdcode = _SetAuth_CMD_;
@@ -1168,25 +1168,25 @@ sint r8712_set_auth(struct _adapter *adapter,
pcmd->rspsz = 0;
INIT_LIST_HEAD(&pcmd->list);
r8712_enqueue_cmd(pcmdpriv, pcmd);
- return _SUCCESS;
+ return 0;
}
-sint r8712_set_key(struct _adapter *adapter,
- struct security_priv *psecuritypriv,
- sint keyid)
+int r8712_set_key(struct _adapter *adapter,
+ struct security_priv *psecuritypriv,
+ sint keyid)
{
struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
struct cmd_obj *pcmd;
struct setkey_parm *psetkeyparm;
u8 keylen;
- sint ret = _SUCCESS;
+ int ret;
pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
if (!pcmd)
- return _FAIL;
+ return -ENOMEM;
psetkeyparm = kzalloc(sizeof(*psetkeyparm), GFP_ATOMIC);
if (!psetkeyparm) {
- ret = _FAIL;
+ ret = -ENOMEM;
goto err_free_cmd;
}
if (psecuritypriv->AuthAlgrthm == 2) { /* 802.1X */
@@ -1211,7 +1211,7 @@ sint r8712_set_key(struct _adapter *adapter,
break;
case _TKIP_:
if (keyid < 1 || keyid > 2) {
- ret = _FAIL;
+ ret = -EINVAL;
goto err_free_parm;
}
keylen = 16;
@@ -1221,7 +1221,7 @@ sint r8712_set_key(struct _adapter *adapter,
break;
case _AES_:
if (keyid < 1 || keyid > 2) {
- ret = _FAIL;
+ ret = -EINVAL;
goto err_free_parm;
}
keylen = 16;
@@ -1230,7 +1230,7 @@ sint r8712_set_key(struct _adapter *adapter,
psetkeyparm->grpkey = 1;
break;
default:
- ret = _FAIL;
+ ret = -EINVAL;
goto err_free_parm;
}
pcmd->cmdcode = _SetKey_CMD_;
@@ -1240,7 +1240,7 @@ sint r8712_set_key(struct _adapter *adapter,
pcmd->rspsz = 0;
INIT_LIST_HEAD(&pcmd->list);
r8712_enqueue_cmd(pcmdpriv, pcmd);
- return ret;
+ return 0;
err_free_parm:
kfree(psetkeyparm);
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h
index a160107e9801..46effb469fd4 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.h
+++ b/drivers/staging/rtl8712/rtl871x_mlme.h
@@ -173,10 +173,10 @@ void r8712_free_network_queue(struct _adapter *adapter);
int r8712_init_mlme_priv(struct _adapter *adapter);
void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv);
int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv);
-sint r8712_set_key(struct _adapter *adapter,
- struct security_priv *psecuritypriv, sint keyid);
-sint r8712_set_auth(struct _adapter *adapter,
- struct security_priv *psecuritypriv);
+int r8712_set_key(struct _adapter *adapter,
+ struct security_priv *psecuritypriv, sint keyid);
+int r8712_set_auth(struct _adapter *adapter,
+ struct security_priv *psecuritypriv);
uint r8712_get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss);
void r8712_generate_random_ibss(u8 *pibss);
u8 *r8712_get_capability_from_ie(u8 *ie);
diff --git a/drivers/staging/rtl8712/rtl871x_mp.c b/drivers/staging/rtl8712/rtl871x_mp.c
index edd3da05fc06..1a39a96b726f 100644
--- a/drivers/staging/rtl8712/rtl871x_mp.c
+++ b/drivers/staging/rtl8712/rtl871x_mp.c
@@ -35,7 +35,7 @@ static void _init_mp_priv_(struct mp_priv *pmp_priv)
static int init_mp_priv(struct mp_priv *pmp_priv)
{
- int i, res;
+ int i;
struct mp_xmit_frame *pmp_xmitframe;
_init_mp_priv_(pmp_priv);
@@ -45,8 +45,7 @@ static int init_mp_priv(struct mp_priv *pmp_priv)
sizeof(struct mp_xmit_frame) + 4,
GFP_ATOMIC);
if (!pmp_priv->pallocated_mp_xmitframe_buf) {
- res = _FAIL;
- goto _exit_init_mp_priv;
+ return -ENOMEM;
}
pmp_priv->pmp_xmtframe_buf = pmp_priv->pallocated_mp_xmitframe_buf +
4 -
@@ -62,9 +61,7 @@ static int init_mp_priv(struct mp_priv *pmp_priv)
pmp_xmitframe++;
}
pmp_priv->free_mp_xmitframe_cnt = NR_MP_XMITFRAME;
- res = _SUCCESS;
-_exit_init_mp_priv:
- return res;
+ return 0;
}
static int free_mp_priv(struct mp_priv *pmp_priv)
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.c b/drivers/staging/rtl8712/rtl871x_pwrctrl.c
index 2beafc7742b3..23cff43437e2 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.c
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.c
@@ -184,19 +184,19 @@ void r8712_init_pwrctrl_priv(struct _adapter *padapter)
* will raise the cpwm to be greater than or equal to P2.
* Calling Context: Passive
* Return Value:
- * _SUCCESS: r8712_cmd_thread can issue cmds to firmware afterwards.
- * _FAIL: r8712_cmd_thread can not do anything.
+ * 0: r8712_cmd_thread can issue cmds to firmware afterwards.
+ * -EINVAL: r8712_cmd_thread can not do anything.
*/
-sint r8712_register_cmd_alive(struct _adapter *padapter)
+int r8712_register_cmd_alive(struct _adapter *padapter)
{
- uint res = _SUCCESS;
+ int res = 0;
struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv;
mutex_lock(&pwrctrl->mutex_lock);
register_task_alive(pwrctrl, CMD_ALIVE);
if (pwrctrl->cpwm < PS_STATE_S2) {
r8712_set_rpwm(padapter, PS_STATE_S3);
- res = _FAIL;
+ res = -EINVAL;
}
mutex_unlock(&pwrctrl->mutex_lock);
return res;
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
index 11b5034f203d..dd5a79f90b1a 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
@@ -104,7 +104,7 @@ struct pwrctrl_priv {
};
void r8712_init_pwrctrl_priv(struct _adapter *adapter);
-sint r8712_register_cmd_alive(struct _adapter *padapter);
+int r8712_register_cmd_alive(struct _adapter *padapter);
void r8712_unregister_cmd_alive(struct _adapter *padapter);
void r8712_cpwm_int_hdl(struct _adapter *padapter,
struct reportpwrstate_parm *preportpwrstate);
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index 5298fe603437..e5092b6da4bd 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -48,7 +48,7 @@ void _r8712_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv)
_init_queue(&psta_recvpriv->defrag_q);
}
-sint _r8712_init_recv_priv(struct recv_priv *precvpriv,
+void _r8712_init_recv_priv(struct recv_priv *precvpriv,
struct _adapter *padapter)
{
sint i;
@@ -64,7 +64,7 @@ sint _r8712_init_recv_priv(struct recv_priv *precvpriv,
sizeof(union recv_frame) + RXFRAME_ALIGN_SZ,
GFP_ATOMIC);
if (precvpriv->pallocated_frame_buf == NULL)
- return _FAIL;
+ return;
kmemleak_not_leak(precvpriv->pallocated_frame_buf);
precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf +
RXFRAME_ALIGN_SZ -
@@ -80,7 +80,7 @@ sint _r8712_init_recv_priv(struct recv_priv *precvpriv,
precvframe++;
}
precvpriv->rx_pending_cnt = 1;
- return r8712_init_recv_priv(precvpriv, padapter);
+ r8712_init_recv_priv(precvpriv, padapter);
}
void _r8712_free_recv_priv(struct recv_priv *precvpriv)
@@ -245,8 +245,7 @@ union recv_frame *r8712_portctrl(struct _adapter *adapter,
if (auth_alg == 2) {
/* get ether_type */
ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE;
- memcpy(&ether_type, ptr, 2);
- be16_to_cpus(&ether_type);
+ ether_type = get_unaligned_be16(ptr);
if ((psta != NULL) && (psta->ieee8021x_blocked)) {
/* blocked
@@ -586,7 +585,7 @@ sint r8712_validate_recv_frame(struct _adapter *adapter,
return retval;
}
-sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
+int r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
{
/*remove the wlanhdr and add the eth_hdr*/
sint rmv_len;
@@ -629,14 +628,14 @@ sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
ptr = recvframe_pull(precvframe, (rmv_len -
sizeof(struct ethhdr) + 2) - 24);
if (!ptr)
- return _FAIL;
+ return -ENOMEM;
memcpy(ptr, get_rxmem(precvframe), 24);
ptr += 24;
} else {
ptr = recvframe_pull(precvframe, (rmv_len -
sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
if (!ptr)
- return _FAIL;
+ return -ENOMEM;
}
memcpy(ptr, pattrib->dst, ETH_ALEN);
@@ -646,10 +645,10 @@ sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
memcpy(ptr + 12, &be_tmp, 2);
}
- return _SUCCESS;
+ return 0;
}
-s32 r8712_recv_entry(union recv_frame *precvframe)
+void r8712_recv_entry(union recv_frame *precvframe)
{
struct _adapter *padapter;
struct recv_priv *precvpriv;
@@ -667,9 +666,8 @@ s32 r8712_recv_entry(union recv_frame *precvframe)
precvpriv->rx_pkts++;
precvpriv->rx_bytes += (uint)(precvframe->u.hdr.rx_tail -
precvframe->u.hdr.rx_data);
- return ret;
+ return;
_recv_entry_drop:
precvpriv->rx_drop++;
padapter->mppriv.rx_pktloss = precvpriv->rx_drop;
- return ret;
}
diff --git a/drivers/staging/rtl8712/rtl871x_recv.h b/drivers/staging/rtl8712/rtl871x_recv.h
index f87b2ff5de1c..0146a774e19d 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.h
+++ b/drivers/staging/rtl8712/rtl871x_recv.h
@@ -128,7 +128,7 @@ struct sta_recv_priv {
/* get a free recv_frame from pfree_recv_queue */
union recv_frame *r8712_alloc_recvframe(struct __queue *pfree_recv_queue);
-int r8712_free_recvframe(union recv_frame *precvframe,
+void r8712_free_recvframe(union recv_frame *precvframe,
struct __queue *pfree_recv_queue);
void r8712_free_recvframe_queue(struct __queue *pframequeue,
struct __queue *pfree_recv_queue);
diff --git a/drivers/staging/rtl8712/rtl871x_rf.h b/drivers/staging/rtl8712/rtl871x_rf.h
index cc54453cd424..7d98921a48fa 100644
--- a/drivers/staging/rtl8712/rtl871x_rf.h
+++ b/drivers/staging/rtl8712/rtl871x_rf.h
@@ -52,5 +52,4 @@ enum {
RTL8712_RFC_2T2R = 0x22
};
-#endif /*_RTL8711_RF_H_*/
-
+#endif /*__RTL871X_RF_H_*/
diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c
index 693008bba83e..73e3d5ef3af2 100644
--- a/drivers/staging/rtl8712/rtl871x_security.c
+++ b/drivers/staging/rtl8712/rtl871x_security.c
@@ -636,7 +636,7 @@ u32 r8712_tkip_encrypt(struct _adapter *padapter, u8 *pxmitframe)
}
/* The hlen doesn't include the IV */
-u32 r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe)
+void r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe)
{ /* exclude ICV */
u16 pnl;
u32 pnh;
@@ -670,7 +670,7 @@ u32 r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe)
prwskey = &psecuritypriv->XGrpKey[
((idx >> 6) & 0x3) - 1].skey[0];
if (!psecuritypriv->binstallGrpkey)
- return _FAIL;
+ return;
} else {
prwskey = &stainfo->x_UncstKey.skey[0];
}
@@ -686,16 +686,8 @@ u32 r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe)
arcfour_encrypt(&mycontext, payload, payload, length);
*((__le32 *)crc) = cpu_to_le32(getcrc32(payload,
length - 4));
- if (crc[3] != payload[length - 1] ||
- crc[2] != payload[length - 2] ||
- crc[1] != payload[length - 3] ||
- crc[0] != payload[length - 4])
- return _FAIL;
- } else {
- return _FAIL;
}
}
- return _SUCCESS;
}
/* 3 =====AES related===== */
@@ -1019,8 +1011,8 @@ static void bitwise_xor(u8 *ina, u8 *inb, u8 *out)
out[i] = ina[i] ^ inb[i];
}
-static sint aes_cipher(u8 *key, uint hdrlen,
- u8 *pframe, uint plen)
+static void aes_cipher(u8 *key, uint hdrlen,
+ u8 *pframe, uint plen)
{
uint qc_exists, a4_exists, i, j, payload_remainder;
uint num_blocks, payload_index;
@@ -1140,7 +1132,6 @@ static sint aes_cipher(u8 *key, uint hdrlen,
bitwise_xor(aes_out, padded_buffer, chain_buffer);
for (j = 0; j < 8; j++)
pframe[payload_index++] = chain_buffer[j];
- return _SUCCESS;
}
u32 r8712_aes_encrypt(struct _adapter *padapter, u8 *pxmitframe)
@@ -1193,8 +1184,8 @@ u32 r8712_aes_encrypt(struct _adapter *padapter, u8 *pxmitframe)
return res;
}
-static sint aes_decipher(u8 *key, uint hdrlen,
- u8 *pframe, uint plen)
+static void aes_decipher(u8 *key, uint hdrlen,
+ u8 *pframe, uint plen)
{
static u8 message[MAX_MSG_SIZE];
uint qc_exists, a4_exists, i, j, payload_remainder;
@@ -1348,10 +1339,9 @@ static sint aes_decipher(u8 *key, uint hdrlen,
for (j = 0; j < 8; j++)
message[payload_index++] = chain_buffer[j];
/* compare the mic */
- return _SUCCESS;
}
-u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe)
+void r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe)
{ /* exclude ICV */
/* Intermediate Buffers */
sint length;
@@ -1374,7 +1364,7 @@ u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe)
prwskey = &psecuritypriv->XGrpKey[
((idx >> 6) & 0x3) - 1].skey[0];
if (!psecuritypriv->binstallGrpkey)
- return _FAIL;
+ return;
} else {
prwskey = &stainfo->x_UncstKey.skey[0];
@@ -1384,11 +1374,8 @@ u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe)
prxattrib->iv_len;
aes_decipher(prwskey, prxattrib->hdrlen, pframe,
length);
- } else {
- return _FAIL;
}
}
- return _SUCCESS;
}
void r8712_use_tkipkey_handler(struct timer_list *t)
diff --git a/drivers/staging/rtl8712/rtl871x_security.h b/drivers/staging/rtl8712/rtl871x_security.h
index 25b4d379766d..b2dda16cbd0a 100644
--- a/drivers/staging/rtl8712/rtl871x_security.h
+++ b/drivers/staging/rtl8712/rtl871x_security.h
@@ -209,8 +209,8 @@ void r8712_secgetmic(struct mic_data *pmicdata, u8 *dst);
u32 r8712_aes_encrypt(struct _adapter *padapter, u8 *pxmitframe);
u32 r8712_tkip_encrypt(struct _adapter *padapter, u8 *pxmitframe);
void r8712_wep_encrypt(struct _adapter *padapter, u8 *pxmitframe);
-u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe);
-u32 r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe);
+void r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe);
+void r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe);
void r8712_wep_decrypt(struct _adapter *padapter, u8 *precvframe);
void r8712_use_tkipkey_handler(struct timer_list *t);
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index 0a26d71e5340..cc5809e49e35 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -49,8 +49,8 @@ void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv)
INIT_LIST_HEAD(&psta_xmitpriv->apsd);
}
-sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
- struct _adapter *padapter)
+int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
+ struct _adapter *padapter)
{
sint i;
struct xmit_buf *pxmitbuf;
@@ -79,7 +79,7 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
kmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4, GFP_ATOMIC);
if (!pxmitpriv->pallocated_frame_buf) {
pxmitpriv->pxmit_frame_buf = NULL;
- return _FAIL;
+ return -ENOMEM;
}
pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 -
((addr_t) (pxmitpriv->pallocated_frame_buf) & 3);
@@ -119,7 +119,7 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
if (!pxmitpriv->pallocated_xmitbuf) {
kfree(pxmitpriv->pallocated_frame_buf);
pxmitpriv->pallocated_frame_buf = NULL;
- return _FAIL;
+ return -ENOMEM;
}
pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 -
((addr_t)(pxmitpriv->pallocated_xmitbuf) & 3);
@@ -129,12 +129,12 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
pxmitbuf->pallocated_buf = kmalloc(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ,
GFP_ATOMIC);
if (!pxmitbuf->pallocated_buf)
- return _FAIL;
+ return -ENOMEM;
pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ -
((addr_t) (pxmitbuf->pallocated_buf) &
(XMITBUF_ALIGN_SZ - 1));
if (r8712_xmit_resource_alloc(padapter, pxmitbuf))
- return _FAIL;
+ return -ENOMEM;
list_add_tail(&pxmitbuf->list,
&(pxmitpriv->free_xmitbuf_queue.queue));
pxmitbuf++;
@@ -146,7 +146,7 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
tasklet_init(&pxmitpriv->xmit_tasklet,
(void(*)(unsigned long))r8712_xmit_bh,
(unsigned long)padapter);
- return _SUCCESS;
+ return 0;
}
void _free_xmit_priv(struct xmit_priv *pxmitpriv)
@@ -173,8 +173,8 @@ void _free_xmit_priv(struct xmit_priv *pxmitpriv)
free_hwxmits(padapter);
}
-sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
- struct pkt_attrib *pattrib)
+int r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
+ struct pkt_attrib *pattrib)
{
struct pkt_file pktfile;
struct sta_info *psta = NULL;
@@ -224,7 +224,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
} else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
/*firstly, filter packet not belongs to mp*/
if (pattrib->ether_type != 0x8712)
- return _FAIL;
+ return -EINVAL;
/* for mp storing the txcmd per packet,
* according to the info of txcmd to update pattrib
*/
@@ -271,7 +271,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
} else {
psta = r8712_get_stainfo(pstapriv, pattrib->ra);
if (psta == NULL) /* drop the pkt */
- return _FAIL;
+ return -ENOMEM;
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
pattrib->mac_id = 5;
else
@@ -283,7 +283,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
pattrib->psta = psta;
} else {
/* if we cannot get psta => drrp the pkt */
- return _FAIL;
+ return -ENOMEM;
}
pattrib->ack_policy = 0;
@@ -301,7 +301,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
pattrib->encrypt = 0;
if ((pattrib->ether_type != 0x888e) &&
!check_fwstate(pmlmepriv, WIFI_MP_STATE))
- return _FAIL;
+ return -EINVAL;
} else {
GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast);
}
@@ -315,7 +315,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
pattrib->iv_len = 8;
pattrib->icv_len = 4;
if (padapter->securitypriv.busetkipkey == _FAIL)
- return _FAIL;
+ return -EINVAL;
break;
case _AES_:
pattrib->iv_len = 8;
@@ -339,11 +339,11 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
if (check_fwstate(pmlmepriv, WIFI_MP_STATE))
pattrib->priority =
(le32_to_cpu(txdesc.txdw1) >> QSEL_SHT) & 0x1f;
- return _SUCCESS;
+ return 0;
}
-static sint xmitframe_addmic(struct _adapter *padapter,
- struct xmit_frame *pxmitframe)
+static int xmitframe_addmic(struct _adapter *padapter,
+ struct xmit_frame *pxmitframe)
{
u32 curfragnum, length;
u8 *pframe, *payload, mic[8];
@@ -372,7 +372,7 @@ static sint xmitframe_addmic(struct _adapter *padapter,
if (!memcmp(psecuritypriv->XGrptxmickey
[psecuritypriv->XGrpKeyid].skey,
null_key, 16))
- return _FAIL;
+ return -ENOMEM;
/*start to calculate the mic code*/
r8712_secmicsetkey(&micdata,
psecuritypriv->
@@ -381,7 +381,7 @@ static sint xmitframe_addmic(struct _adapter *padapter,
} else {
if (!memcmp(&stainfo->tkiptxmickey.skey[0],
null_key, 16))
- return _FAIL;
+ return -ENOMEM;
/* start to calculate the mic code */
r8712_secmicsetkey(&micdata,
&stainfo->tkiptxmickey.skey[0]);
@@ -442,7 +442,7 @@ static sint xmitframe_addmic(struct _adapter *padapter,
payload = payload - pattrib->last_txcmdsz + 8;
}
}
- return _SUCCESS;
+ return 0;
}
static sint xmitframe_swencrypt(struct _adapter *padapter,
@@ -469,8 +469,8 @@ static sint xmitframe_swencrypt(struct _adapter *padapter,
return _SUCCESS;
}
-static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr,
- struct pkt_attrib *pattrib)
+static int make_wlanhdr(struct _adapter *padapter, u8 *hdr,
+ struct pkt_attrib *pattrib)
{
u16 *qc;
@@ -509,7 +509,7 @@ static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr,
memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv),
ETH_ALEN);
} else {
- return _FAIL;
+ return -EINVAL;
}
if (pattrib->encrypt)
@@ -547,7 +547,7 @@ static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr,
}
}
}
- return _SUCCESS;
+ return 0;
}
static sint r8712_put_snap(u8 *data, u16 h_proto)
@@ -605,7 +605,7 @@ sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt,
pbuf_start = pxmitframe->buf_addr;
ptxdesc = pbuf_start;
mem_start = pbuf_start + TXDESC_OFFSET;
- if (make_wlanhdr(padapter, mem_start, pattrib) == _FAIL)
+ if (make_wlanhdr(padapter, mem_start, pattrib))
return _FAIL;
_r8712_open_pktfile(pkt, &pktfile);
_r8712_pktfile_read(&pktfile, NULL, (uint) pattrib->pkt_hdrlen);
@@ -696,7 +696,7 @@ sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt,
memcpy(mem_start, pbuf_start + TXDESC_OFFSET, pattrib->hdrlen);
}
- if (xmitframe_addmic(padapter, pxmitframe) == _FAIL)
+ if (xmitframe_addmic(padapter, pxmitframe))
return _FAIL;
xmitframe_swencrypt(padapter, pxmitframe);
return _SUCCESS;
@@ -753,19 +753,18 @@ struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
return pxmitbuf;
}
-int r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+void r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
{
unsigned long irqL;
struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
if (pxmitbuf == NULL)
- return _FAIL;
+ return;
spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL);
list_del_init(&pxmitbuf->list);
list_add_tail(&(pxmitbuf->list), &pfree_xmitbuf_queue->queue);
pxmitpriv->free_xmitbuf_cnt++;
spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL);
- return _SUCCESS;
}
/*
@@ -894,8 +893,8 @@ static inline struct tx_servq *get_sta_pending(struct _adapter *padapter,
* Will enqueue pxmitframe to the proper queue, and indicate it
* to xx_pending list.....
*/
-sint r8712_xmit_classifier(struct _adapter *padapter,
- struct xmit_frame *pxmitframe)
+int r8712_xmit_classifier(struct _adapter *padapter,
+ struct xmit_frame *pxmitframe)
{
unsigned long irqL0;
struct __queue *pstapending;
@@ -920,7 +919,7 @@ sint r8712_xmit_classifier(struct _adapter *padapter,
}
}
if (psta == NULL)
- return _FAIL;
+ return -EINVAL;
ptxservq = get_sta_pending(padapter, &pstapending,
psta, pattrib->priority);
spin_lock_irqsave(&pstapending->lock, irqL0);
@@ -929,7 +928,7 @@ sint r8712_xmit_classifier(struct _adapter *padapter,
list_add_tail(&pxmitframe->list, &ptxservq->sta_pending.queue);
ptxservq->qcnt++;
spin_unlock_irqrestore(&pstapending->lock, irqL0);
- return _SUCCESS;
+ return 0;
}
static void alloc_hwxmits(struct _adapter *padapter)
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h
index 4199cb586fb1..b14da38bf652 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.h
+++ b/drivers/staging/rtl8712/rtl871x_xmit.h
@@ -41,7 +41,7 @@ do { \
pattrib_iv[0] = txpn._byte_.TSC0;\
pattrib_iv[1] = txpn._byte_.TSC1;\
pattrib_iv[2] = txpn._byte_.TSC2;\
- pattrib_iv[3] = ((keyidx & 0x3)<<6);\
+ pattrib_iv[3] = ((keyidx & 0x3) << 6);\
txpn.val = (txpn.val == 0xffffff) ? 0 : (txpn.val+1);\
} while (0)
@@ -249,8 +249,8 @@ struct xmit_priv {
uint free_xmitbuf_cnt;
};
-int r8712_free_xmitbuf(struct xmit_priv *pxmitpriv,
- struct xmit_buf *pxmitbuf);
+void r8712_free_xmitbuf(struct xmit_priv *pxmitpriv,
+ struct xmit_buf *pxmitbuf);
struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv);
void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len);
struct xmit_frame *r8712_alloc_xmitframe(struct xmit_priv *pxmitpriv);
@@ -258,25 +258,25 @@ void r8712_free_xmitframe(struct xmit_priv *pxmitpriv,
struct xmit_frame *pxmitframe);
void r8712_free_xmitframe_queue(struct xmit_priv *pxmitpriv,
struct __queue *pframequeue);
-sint r8712_xmit_classifier(struct _adapter *padapter,
- struct xmit_frame *pxmitframe);
+int r8712_xmit_classifier(struct _adapter *padapter,
+ struct xmit_frame *pxmitframe);
sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt,
struct xmit_frame *pxmitframe);
sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag);
void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv);
-sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
- struct pkt_attrib *pattrib);
+int r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
+ struct pkt_attrib *pattrib);
int r8712_txframes_sta_ac_pending(struct _adapter *padapter,
struct pkt_attrib *pattrib);
-sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
- struct _adapter *padapter);
+int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
+ struct _adapter *padapter);
void _free_xmit_priv(struct xmit_priv *pxmitpriv);
void r8712_free_xmitframe_ex(struct xmit_priv *pxmitpriv,
struct xmit_frame *pxmitframe);
int r8712_pre_xmit(struct _adapter *padapter, struct xmit_frame *pxmitframe);
int r8712_xmit_enqueue(struct _adapter *padapter,
struct xmit_frame *pxmitframe);
-int r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe);
+void r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe);
void r8712_xmit_bh(void *priv);
void xmitframe_xmitbuf_attach(struct xmit_frame *pxmitframe,
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index d0daae0b8299..ba1288297ee4 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -389,7 +389,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
}
/* step 4. */
status = r8712_init_drv_sw(padapter);
- if (status == _FAIL)
+ if (status)
goto error;
/* step 5. read efuse/eeprom data and get mac_addr */
{
diff --git a/drivers/staging/rtl8712/usb_osintf.h b/drivers/staging/rtl8712/usb_osintf.h
index ddfa405d0c9b..2e512b4a564c 100644
--- a/drivers/staging/rtl8712/usb_osintf.h
+++ b/drivers/staging/rtl8712/usb_osintf.h
@@ -28,8 +28,8 @@ void rtl871x_intf_stop(struct _adapter *padapter);
void r871x_dev_unload(struct _adapter *padapter);
void r8712_stop_drv_threads(struct _adapter *padapter);
void r8712_stop_drv_timers(struct _adapter *padapter);
-u8 r8712_init_drv_sw(struct _adapter *padapter);
-u8 r8712_free_drv_sw(struct _adapter *padapter);
+int r8712_init_drv_sw(struct _adapter *padapter);
+void r8712_free_drv_sw(struct _adapter *padapter);
struct net_device *r8712_init_netdev(void);
#endif
diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h
index 1a5b966a167e..be731f1a2209 100644
--- a/drivers/staging/rtl8712/wifi.h
+++ b/drivers/staging/rtl8712/wifi.h
@@ -300,7 +300,6 @@ static inline unsigned char *get_da(unsigned char *pframe)
return da;
}
-
static inline unsigned char *get_sa(unsigned char *pframe)
{
unsigned char *sa;
@@ -346,8 +345,6 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe)
return sa;
}
-
-
/*-----------------------------------------------------------------------------
* Below is for the security related definition
*-----------------------------------------------------------------------------
@@ -392,7 +389,6 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe)
#define _RESERVED47_ 47
-
/* ---------------------------------------------------------------------------
* Below is the fixed elements...
* ---------------------------------------------------------------------------
@@ -436,7 +432,6 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe)
#define _WMM_IE_Length_ 7 /* for WMM STA */
#define _WMM_Para_Element_Length_ 24
-
/*-----------------------------------------------------------------------------
* Below is the definition for 802.11n
*------------------------------------------------------------------------------
@@ -456,7 +451,6 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe)
#define GetOrderBit(pbuf) (((*(__le16 *)(pbuf)) & \
le16_to_cpu(_ORDER_)) != 0)
-
/**
* struct ieee80211_bar - HT Block Ack Request
*
@@ -476,7 +470,6 @@ struct ieee80211_bar {
#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000
#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004
-
/*
* struct ieee80211_ht_cap - HT capabilities
*
@@ -552,7 +545,6 @@ struct ieee80211_ht_addt_info {
*/
#define IEEE80211_MIN_AMPDU_BUF 0x8
-
/* Spatial Multiplexing Power Save Modes */
#define WLAN_HT_CAP_SM_PS_STATIC 0
#define WLAN_HT_CAP_SM_PS_DYNAMIC 1
diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c
index 01d713d027b0..1f67d86c606f 100644
--- a/drivers/staging/rtl8712/xmit_linux.c
+++ b/drivers/staging/rtl8712/xmit_linux.c
@@ -160,7 +160,7 @@ int r8712_xmit_entry(_pkt *pkt, struct net_device *netdev)
if (!xmitframe)
goto _xmit_entry_drop;
- if ((!r8712_update_attrib(adapter, pkt, &xmitframe->attrib)))
+ if (r8712_update_attrib(adapter, pkt, &xmitframe->attrib))
goto _xmit_entry_drop;
adapter->ledpriv.LedControlHandler(adapter, LED_CTL_TX);
diff --git a/drivers/staging/rtl8723bs/Makefile b/drivers/staging/rtl8723bs/Makefile
index a12cf8dd8ed9..dfe410283ca0 100644
--- a/drivers/staging/rtl8723bs/Makefile
+++ b/drivers/staging/rtl8723bs/Makefile
@@ -60,7 +60,6 @@ r8723bs-y = \
os_dep/osdep_service.o \
os_dep/os_intfs.o \
os_dep/recv_linux.o \
- os_dep/rtw_proc.o \
os_dep/sdio_intf.o \
os_dep/sdio_ops_linux.o \
os_dep/wifi_regd.o \
diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c
index 7bd5c61b055c..6d18d23acdc0 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ap.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ap.c
@@ -13,11 +13,10 @@ extern unsigned char RTW_WPA_OUI[];
extern unsigned char WMM_OUI[];
extern unsigned char WPS_OUI[];
extern unsigned char P2P_OUI[];
-extern unsigned char WFD_OUI[];
void init_mlme_ap_info(struct adapter *padapter)
{
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
@@ -34,9 +33,9 @@ void init_mlme_ap_info(struct adapter *padapter)
void free_mlme_ap_info(struct adapter *padapter)
{
struct sta_info *psta = NULL;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
/* stop_ap_mode(padapter); */
@@ -58,9 +57,9 @@ void free_mlme_ap_info(struct adapter *padapter)
static void update_BCNTIM(struct adapter *padapter)
{
struct sta_priv *pstapriv = &padapter->stapriv;
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network;
unsigned char *pie = pnetwork_mlmeext->IEs;
/* DBG_871X("%s\n", __func__); */
@@ -83,7 +82,7 @@ static void update_BCNTIM(struct adapter *padapter)
if (p != NULL && tim_ielen > 0) {
tim_ielen += 2;
- premainder_ie = p+tim_ielen;
+ premainder_ie = p + tim_ielen;
tim_ie_offset = (sint)(p - pie);
@@ -94,7 +93,7 @@ static void update_BCNTIM(struct adapter *padapter)
} else {
tim_ielen = 0;
- /* calucate head_len */
+ /* calculate head_len */
offset = _FIXED_IE_LENGTH_;
/* get ssid_ie len */
@@ -105,7 +104,7 @@ static void update_BCNTIM(struct adapter *padapter)
(pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)
);
if (p != NULL)
- offset += tmp_len+2;
+ offset += tmp_len + 2;
/* get supported rates len */
p = rtw_get_ie(
@@ -114,7 +113,7 @@ static void update_BCNTIM(struct adapter *padapter)
(pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)
);
if (p != NULL)
- offset += tmp_len+2;
+ offset += tmp_len + 2;
/* DS Parameter Set IE, len =3 */
offset += 3;
@@ -135,7 +134,7 @@ static void update_BCNTIM(struct adapter *padapter)
*dst_ie++ = _TIM_IE_;
- if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fe))
+ if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fe))
tim_ielen = 5;
else
tim_ielen = 4;
@@ -143,9 +142,9 @@ static void update_BCNTIM(struct adapter *padapter)
*dst_ie++ = tim_ielen;
*dst_ie++ = 0;/* DTIM count */
- *dst_ie++ = 1;/* DTIM peroid */
+ *dst_ie++ = 1;/* DTIM period */
- if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */
+ if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */
*dst_ie++ = BIT(0);/* bitmap ctrl */
else
*dst_ie++ = 0;
@@ -153,7 +152,7 @@ static void update_BCNTIM(struct adapter *padapter)
if (tim_ielen == 4) {
__le16 pvb;
- if (pstapriv->tim_bitmap&0xff00)
+ if (pstapriv->tim_bitmap & 0xff00)
pvb = cpu_to_le16(pstapriv->tim_bitmap >> 8);
else
pvb = tim_bitmap_le;
@@ -188,8 +187,8 @@ u8 chk_sta_is_alive(struct sta_info *psta)
/* STA_RX_PKTS_ARG(psta) */
, STA_RX_PKTS_DIFF_ARG(psta)
, psta->expire_to
- , psta->state&WIFI_SLEEP_STATE?"PS, ":""
- , psta->state&WIFI_STA_ALIVE_CHK_STATE?"SAC, ":""
+ , psta->state & WIFI_SLEEP_STATE ? "PS, " : ""
+ , psta->state & WIFI_STA_ALIVE_CHK_STATE ? "SAC, " : ""
, psta->sleepq_len
);
#endif
@@ -292,7 +291,7 @@ void expire_timeout_chk(struct adapter *padapter)
if (psta->state & WIFI_SLEEP_STATE) {
if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) {
- /* to check if alive by another methods if staion is at ps mode. */
+ /* to check if alive by another methods if station is at ps mode. */
psta->expire_to = pstapriv->expire_to;
psta->state |= WIFI_STA_ALIVE_CHK_STATE;
@@ -325,10 +324,10 @@ void expire_timeout_chk(struct adapter *padapter)
updated = ap_free_sta(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING);
} else {
/* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
- if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt)
+ if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt)
&& padapter->xmitpriv.free_xmitframe_cnt < ((
- NR_XMITFRAME/pstapriv->asoc_list_cnt
- )/2)
+ NR_XMITFRAME / pstapriv->asoc_list_cnt
+ ) / 2)
) {
DBG_871X(
"%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n",
@@ -586,8 +585,8 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable;
phtpriv_sta->rx_ampdu_min_spacing = (
- phtpriv_sta->ht_cap.ampdu_params_info&IEEE80211_HT_CAP_AMPDU_DENSITY
- )>>2;
+ phtpriv_sta->ht_cap.ampdu_params_info & IEEE80211_HT_CAP_AMPDU_DENSITY
+ ) >> 2;
/* bwmode */
if ((
@@ -782,8 +781,8 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf)
/* check if there is wps ie, */
/* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */
/* and at first time the security ie (RSN/WPA IE) will not include in beacon. */
- if (!rtw_get_wps_ie(pnetwork->IEs+_FIXED_IE_LENGTH_,
- pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL))
+ if (!rtw_get_wps_ie(pnetwork->IEs + _FIXED_IE_LENGTH_,
+ pnetwork->IELength - _FIXED_IE_LENGTH_, NULL, NULL))
pmlmeext->bstart_bss = true;
/* todo: update wmm, ht cap */
@@ -861,7 +860,7 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf)
(pnetwork->IELength - sizeof(struct ndis_802_11_fix_ie))
);
if (p && ie_len) {
- pht_info = (struct HT_info_element *)(p+2);
+ pht_info = (struct HT_info_element *)(p + 2);
if (cur_channel > 14) {
if ((pregpriv->bw_mode & 0xf0) > 0)
@@ -916,7 +915,7 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf)
UpdateBrateTbl(padapter, pnetwork->SupportedRates);
rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
- /* udpate capability after cur_wireless_mode updated */
+ /* update capability after cur_wireless_mode updated */
update_capinfo(
padapter,
rtw_get_capability((struct wlan_bssid_ex *)pnetwork)
@@ -1015,7 +1014,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
pbss_network->Ssid.SsidLength = ie_len;
}
- /* chnnel */
+ /* channel */
channel = 0;
pbss_network->Configuration.Length = 0;
p = rtw_get_ie(
@@ -1037,7 +1036,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
(pbss_network->IELength - _BEACON_IE_OFFSET_)
);
if (p != NULL) {
- memcpy(supportRate, p+2, ie_len);
+ memcpy(supportRate, p + 2, ie_len);
supportRateNum = ie_len;
}
@@ -1049,7 +1048,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
pbss_network->IELength - _BEACON_IE_OFFSET_
);
if (p != NULL) {
- memcpy(supportRate+supportRateNum, p+2, ie_len);
+ memcpy(supportRate + supportRateNum, p + 2, ie_len);
supportRateNum += ie_len;
}
@@ -1088,7 +1087,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
if (p && ie_len > 0) {
if (rtw_parse_wpa2_ie(
p,
- ie_len+2,
+ ie_len + 2,
&group_cipher,
&pairwise_cipher,
NULL
@@ -1115,10 +1114,10 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
&ie_len,
(pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))
);
- if ((p) && (!memcmp(p+2, OUI1, 4))) {
+ if ((p) && (!memcmp(p + 2, OUI1, 4))) {
if (rtw_parse_wpa_ie(
p,
- ie_len+2,
+ ie_len + 2,
&group_cipher,
&pairwise_cipher,
NULL
@@ -1151,10 +1150,10 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
&ie_len,
(pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))
);
- if ((p) && !memcmp(p+2, WMM_PARA_IE, 6)) {
+ if ((p) && !memcmp(p + 2, WMM_PARA_IE, 6)) {
pmlmepriv->qospriv.qos_option = 1;
- *(p+8) |= BIT(7);/* QoS Info, support U-APSD */
+ *(p + 8) |= BIT(7);/* QoS Info, support U-APSD */
/* disable all ACM bits since the WMM admission control is not supported */
*(p + 10) &= ~BIT(4); /* BE */
@@ -1180,7 +1179,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
if (p && ie_len > 0) {
u8 rf_type = 0;
u8 max_rx_ampdu_factor = 0;
- struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p+2);
+ struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);
pHT_caps_ie = p;
@@ -1205,14 +1204,14 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
pht_cap->cap_info &= cpu_to_le16(~(IEEE80211_HT_CAP_RX_STBC_3R));
pht_cap->ampdu_params_info &= ~(
- IEEE80211_HT_CAP_AMPDU_FACTOR|IEEE80211_HT_CAP_AMPDU_DENSITY
+ IEEE80211_HT_CAP_AMPDU_FACTOR | IEEE80211_HT_CAP_AMPDU_DENSITY
);
if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
(psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) {
- pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2));
+ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & (0x07 << 2));
} else {
- pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00);
+ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00);
}
rtw_hal_get_def_var(
@@ -1230,7 +1229,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
pht_cap->supp_mcs_set[1] = 0x0;
}
- memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len);
+ memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len);
}
/* parsing HT_INFO_IE */
@@ -1265,8 +1264,8 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
pmlmepriv->htpriv.ht_option = false;
- if ((psecuritypriv->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) ||
- (psecuritypriv->wpa_pairwise_cipher&WPA_CIPHER_TKIP)) {
+ if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
+ (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) {
/* todo: */
/* ht_cap = false; */
}
@@ -1341,7 +1340,7 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
MAC_ARG(addr)
);
- if ((NUM_ACL-1) < pacl_list->num)
+ if ((NUM_ACL - 1) < pacl_list->num)
return (-1);
spin_lock_bh(&(pacl_node_q->lock));
@@ -1454,7 +1453,7 @@ u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta)
psetstakey_para = rtw_zmalloc(sizeof(struct set_stakey_parm));
if (psetstakey_para == NULL) {
- kfree((u8 *) ph2c);
+ kfree((u8 *)ph2c);
res = _FAIL;
goto exit;
}
@@ -1604,10 +1603,10 @@ static void update_bcn_erpinfo_ie(struct adapter *padapter)
struct ndis_80211_var_ie *pIE = (struct ndis_80211_var_ie *)p;
if (pmlmepriv->num_sta_non_erp == 1)
- pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION;
+ pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION;
else
pIE->data[0] &= ~(
- RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION
+ RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION
);
if (pmlmepriv->num_sta_no_short_preamble > 0)
@@ -1662,8 +1661,8 @@ static void update_bcn_wps_ie(struct adapter *padapter)
DBG_871X("%s\n", __func__);
pwps_ie = rtw_get_wps_ie(
- ie+_FIXED_IE_LENGTH_,
- ielen-_FIXED_IE_LENGTH_,
+ ie + _FIXED_IE_LENGTH_,
+ ielen - _FIXED_IE_LENGTH_,
NULL,
&wps_ielen
);
@@ -1675,7 +1674,7 @@ static void update_bcn_wps_ie(struct adapter *padapter)
if (pwps_ie_src == NULL)
return;
- wps_offset = (uint)(pwps_ie-ie);
+ wps_offset = (uint)(pwps_ie - ie);
premainder_ie = pwps_ie + wps_ielen;
@@ -1688,22 +1687,22 @@ static void update_bcn_wps_ie(struct adapter *padapter)
}
wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */
- if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) {
- memcpy(pwps_ie, pwps_ie_src, wps_ielen+2);
+ if ((wps_offset + wps_ielen + 2 + remainder_ielen) <= MAX_IE_SZ) {
+ memcpy(pwps_ie, pwps_ie_src, wps_ielen + 2);
pwps_ie += (wps_ielen+2);
if (pbackup_remainder_ie)
memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
/* update IELength */
- pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen;
+ pnetwork->IELength = wps_offset + (wps_ielen + 2) + remainder_ielen;
}
kfree(pbackup_remainder_ie);
/* deal with the case without set_tx_beacon_cmd() in update_beacon() */
#if defined(CONFIG_INTERRUPT_BASED_TXBCN)
- if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
u8 sr = 0;
rtw_get_wps_attr_content(
@@ -1827,7 +1826,7 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
/*
op_mode
-Set to 0 (HT pure) under the followign conditions
+Set to 0 (HT pure) under the following conditions
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
Set to 1 (HT non-member protection) if there may be non-HT STAs
@@ -2196,7 +2195,7 @@ void rtw_sta_flush(struct adapter *padapter)
DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
- if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+ if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
return;
spin_lock_bh(&pstapriv->asoc_list_lock);
@@ -2230,7 +2229,7 @@ void sta_info_update(struct adapter *padapter, struct sta_info *psta)
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
/* update wmm cap. */
- if (WLAN_STA_WME&flags)
+ if (WLAN_STA_WME & flags)
psta->qos_option = 1;
else
psta->qos_option = 0;
@@ -2239,7 +2238,7 @@ void sta_info_update(struct adapter *padapter, struct sta_info *psta)
psta->qos_option = 0;
/* update 802.11n ht cap. */
- if (WLAN_STA_HT&flags) {
+ if (WLAN_STA_HT & flags) {
psta->htpriv.ht_option = true;
psta->qos_option = 1;
} else {
diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c
index addc55706a3c..8d93c2f26890 100644
--- a/drivers/staging/rtl8723bs/core/rtw_cmd.c
+++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c
@@ -402,7 +402,7 @@ int rtw_cmd_thread(void *context)
{
u8 ret;
struct cmd_obj *pcmd;
- u8 *pcmdbuf, *prspbuf;
+ u8 *pcmdbuf;
unsigned long cmd_start_time;
unsigned long cmd_process_time;
u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
@@ -414,7 +414,6 @@ int rtw_cmd_thread(void *context)
thread_enter("RTW_CMD_THREAD");
pcmdbuf = pcmdpriv->cmd_buf;
- prspbuf = pcmdpriv->rsp_buf;
pcmdpriv->stop_req = 0;
atomic_set(&(pcmdpriv->cmdthd_running), true);
@@ -768,7 +767,7 @@ exit:
u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
{
- u8 *auth, res = _SUCCESS;
+ u8 res = _SUCCESS;
uint t_len = 0;
struct wlan_bssid_ex *psecnetwork;
struct cmd_obj *pcmd;
@@ -825,7 +824,6 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
- auth = &psecuritypriv->authenticator_ie[0];
psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
if ((psecnetwork->IELength-12) < (256-1)) {
@@ -1819,11 +1817,6 @@ static void rtw_btinfo_hdl(struct adapter *adapter, u8 *buf, u16 buf_len)
len = info->len;
}
-/* define DBG_PROC_SET_BTINFO_EVT */
-#ifdef DBG_PROC_SET_BTINFO_EVT
- btinfo_evt_dump(RTW_DBGDUMP, info);
-#endif
-
/* transform BT-FW btinfo to WiFI-FW C2H format and notify */
if (cmd_idx == BTINFO_WIFI_FETCH)
buf[1] = 0;
diff --git a/drivers/staging/rtl8723bs/core/rtw_debug.c b/drivers/staging/rtl8723bs/core/rtw_debug.c
index 695a85999270..c48a8b80af4c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_debug.c
+++ b/drivers/staging/rtl8723bs/core/rtw_debug.c
@@ -132,1310 +132,3 @@ void rf_reg_dump(void *sel, struct adapter *adapter)
}
}
}
-
-#ifdef PROC_DEBUG
-ssize_t proc_set_write_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- char tmp[32];
- u32 addr, val, len;
-
- if (count < 3) {
- DBG_871X("argument size is less than 3\n");
- return -EFAULT;
- }
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
-
- if (num != 3) {
- DBG_871X("invalid write_reg parameter!\n");
- return count;
- }
-
- switch (len) {
- case 1:
- rtw_write8(padapter, addr, (u8)val);
- break;
- case 2:
- rtw_write16(padapter, addr, (u16)val);
- break;
- case 4:
- rtw_write32(padapter, addr, val);
- break;
- default:
- DBG_871X("error write length =%d", len);
- break;
- }
-
- }
-
- return count;
-
-}
-
-static u32 proc_get_read_addr = 0xeeeeeeee;
-static u32 proc_get_read_len = 0x4;
-
-int proc_get_read_reg(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- if (proc_get_read_addr == 0xeeeeeeee) {
- DBG_871X_SEL_NL(m, "address not initialized\n");
- return 0;
- }
-
- switch (proc_get_read_len) {
- case 1:
- DBG_871X_SEL_NL(m, "rtw_read8(0x%x) = 0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr));
- break;
- case 2:
- DBG_871X_SEL_NL(m, "rtw_read16(0x%x) = 0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr));
- break;
- case 4:
- DBG_871X_SEL_NL(m, "rtw_read32(0x%x) = 0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr));
- break;
- default:
- DBG_871X_SEL_NL(m, "error read length =%d\n", proc_get_read_len);
- break;
- }
-
- return 0;
-}
-
-ssize_t proc_set_read_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- char tmp[16];
- u32 addr, len;
-
- if (count < 2) {
- DBG_871X("argument size is less than 2\n");
- return -EFAULT;
- }
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%x %x", &addr, &len);
-
- if (num != 2) {
- DBG_871X("invalid read_reg parameter!\n");
- return count;
- }
-
- proc_get_read_addr = addr;
-
- proc_get_read_len = len;
- }
-
- return count;
-
-}
-
-int proc_get_fwstate(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
-
- DBG_871X_SEL_NL(m, "fwstate = 0x%x\n", get_fwstate(pmlmepriv));
-
- return 0;
-}
-
-int proc_get_sec_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct security_priv *sec = &padapter->securitypriv;
-
- DBG_871X_SEL_NL(m, "auth_alg = 0x%x, enc_alg = 0x%x, auth_type = 0x%x, enc_type = 0x%x\n",
- sec->dot11AuthAlgrthm, sec->dot11PrivacyAlgrthm,
- sec->ndisauthtype, sec->ndisencryptstatus);
-
- DBG_871X_SEL_NL(m, "hw_decrypted =%d\n", sec->hw_decrypted);
-
-#ifdef DBG_SW_SEC_CNT
- DBG_871X_SEL_NL(m, "wep_sw_enc_cnt =%llu, %llu, %llu\n"
- , sec->wep_sw_enc_cnt_bc, sec->wep_sw_enc_cnt_mc, sec->wep_sw_enc_cnt_uc);
- DBG_871X_SEL_NL(m, "wep_sw_dec_cnt =%llu, %llu, %llu\n"
- , sec->wep_sw_dec_cnt_bc, sec->wep_sw_dec_cnt_mc, sec->wep_sw_dec_cnt_uc);
-
- DBG_871X_SEL_NL(m, "tkip_sw_enc_cnt =%llu, %llu, %llu\n"
- , sec->tkip_sw_enc_cnt_bc, sec->tkip_sw_enc_cnt_mc, sec->tkip_sw_enc_cnt_uc);
- DBG_871X_SEL_NL(m, "tkip_sw_dec_cnt =%llu, %llu, %llu\n"
- , sec->tkip_sw_dec_cnt_bc, sec->tkip_sw_dec_cnt_mc, sec->tkip_sw_dec_cnt_uc);
-
- DBG_871X_SEL_NL(m, "aes_sw_enc_cnt =%llu, %llu, %llu\n"
- , sec->aes_sw_enc_cnt_bc, sec->aes_sw_enc_cnt_mc, sec->aes_sw_enc_cnt_uc);
- DBG_871X_SEL_NL(m, "aes_sw_dec_cnt =%llu, %llu, %llu\n"
- , sec->aes_sw_dec_cnt_bc, sec->aes_sw_dec_cnt_mc, sec->aes_sw_dec_cnt_uc);
-#endif /* DBG_SW_SEC_CNT */
-
- return 0;
-}
-
-int proc_get_mlmext_state(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-
- DBG_871X_SEL_NL(m, "pmlmeinfo->state = 0x%x\n", pmlmeinfo->state);
-
- return 0;
-}
-
-int proc_get_roam_flags(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- DBG_871X_SEL_NL(m, "0x%02x\n", rtw_roam_flags(adapter));
-
- return 0;
-}
-
-ssize_t proc_set_roam_flags(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- char tmp[32];
- u8 flags;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%hhx", &flags);
-
- if (num == 1)
- rtw_assign_roam_flags(adapter, flags);
- }
-
- return count;
-
-}
-
-int proc_get_roam_param(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_priv *mlme = &adapter->mlmepriv;
-
- DBG_871X_SEL_NL(m, "%12s %12s %11s\n", "rssi_diff_th", "scanr_exp_ms", "scan_int_ms");
- DBG_871X_SEL_NL(m, "%-12u %-12u %-11u\n"
- , mlme->roam_rssi_diff_th
- , mlme->roam_scanr_exp_ms
- , mlme->roam_scan_int_ms
- );
-
- return 0;
-}
-
-ssize_t proc_set_roam_param(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_priv *mlme = &adapter->mlmepriv;
-
- char tmp[32];
- u8 rssi_diff_th;
- u32 scanr_exp_ms;
- u32 scan_int_ms;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%hhu %u %u", &rssi_diff_th, &scanr_exp_ms, &scan_int_ms);
-
- if (num >= 1)
- mlme->roam_rssi_diff_th = rssi_diff_th;
- if (num >= 2)
- mlme->roam_scanr_exp_ms = scanr_exp_ms;
- if (num >= 3)
- mlme->roam_scan_int_ms = scan_int_ms;
- }
-
- return count;
-
-}
-
-ssize_t proc_set_roam_tgt_addr(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- char tmp[32];
- u8 addr[ETH_ALEN];
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", addr, addr+1, addr+2, addr+3, addr+4, addr+5);
- if (num == 6)
- memcpy(adapter->mlmepriv.roam_tgt_addr, addr, ETH_ALEN);
-
- DBG_871X("set roam_tgt_addr to "MAC_FMT"\n", MAC_ARG(adapter->mlmepriv.roam_tgt_addr));
- }
-
- return count;
-}
-
-int proc_get_qos_option(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
-
- DBG_871X_SEL_NL(m, "qos_option =%d\n", pmlmepriv->qospriv.qos_option);
-
- return 0;
-}
-
-int proc_get_ht_option(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
-
- DBG_871X_SEL_NL(m, "ht_option =%d\n", pmlmepriv->htpriv.ht_option);
-
- return 0;
-}
-
-int proc_get_rf_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
-
- DBG_871X_SEL_NL(m, "cur_ch =%d, cur_bw =%d, cur_ch_offet =%d\n",
- pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
-
- DBG_871X_SEL_NL(m, "oper_ch =%d, oper_bw =%d, oper_ch_offet =%d\n",
- rtw_get_oper_ch(padapter), rtw_get_oper_bw(padapter), rtw_get_oper_choffset(padapter));
-
- return 0;
-}
-
-int proc_get_survey_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct __queue *queue = &(pmlmepriv->scanned_queue);
- struct wlan_network *pnetwork = NULL;
- struct list_head *plist, *phead;
- s32 notify_signal;
- s16 notify_noise = 0;
- u16 index = 0;
-
- spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
- phead = get_list_head(queue);
- plist = phead ? get_next(phead) : NULL;
- if ((!phead) || (!plist)) {
- spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
- return 0;
- }
-
- DBG_871X_SEL_NL(m, "%5s %-17s %3s %-3s %-4s %-4s %5s %s\n", "index", "bssid", "ch", "RSSI", "SdBm", "Noise", "age", "ssid");
- while (1) {
- if (phead == plist)
- break;
-
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
-
- if (!pnetwork)
- break;
-
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true &&
- is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) {
- notify_signal = translate_percentage_to_dbm(padapter->recvpriv.signal_strength);/*dbm*/
- } else {
- notify_signal = translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength);/*dbm*/
- }
-
- #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR)
- rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &(pnetwork->network.Configuration.DSConfig), &(notify_noise));
- #endif
-
- DBG_871X_SEL_NL(m, "%5d "MAC_FMT" %3d %3d %4d %4d %5d %s\n",
- ++index,
- MAC_ARG(pnetwork->network.MacAddress),
- pnetwork->network.Configuration.DSConfig,
- (int)pnetwork->network.Rssi,
- notify_signal,
- notify_noise,
- jiffies_to_msecs(jiffies - pnetwork->last_scanned),
- /*translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength),*/
- pnetwork->network.Ssid.Ssid);
- plist = get_next(plist);
- }
- spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
-
- return 0;
-}
-
-int proc_get_ap_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct sta_info *psta;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct wlan_network *cur_network = &(pmlmepriv->cur_network);
- struct sta_priv *pstapriv = &padapter->stapriv;
-
- psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
- if (psta) {
- int i;
- struct recv_reorder_ctrl *preorder_ctrl;
-
- DBG_871X_SEL_NL(m, "SSID =%s\n", cur_network->network.Ssid.Ssid);
- DBG_871X_SEL_NL(m, "sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr));
- DBG_871X_SEL_NL(m, "cur_channel =%d, cur_bwmode =%d, cur_ch_offset =%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
- DBG_871X_SEL_NL(m, "wireless_mode = 0x%x, rtsen =%d, cts2slef =%d\n", psta->wireless_mode, psta->rtsen, psta->cts2self);
- DBG_871X_SEL_NL(m, "state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
- DBG_871X_SEL_NL(m, "qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
- DBG_871X_SEL_NL(m, "bwmode =%d, ch_offset =%d, sgi_20m =%d, sgi_40m =%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m);
- DBG_871X_SEL_NL(m, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
- DBG_871X_SEL_NL(m, "agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
- DBG_871X_SEL_NL(m, "ldpc_cap = 0x%x, stbc_cap = 0x%x, beamform_cap = 0x%x\n", psta->htpriv.ldpc_cap, psta->htpriv.stbc_cap, psta->htpriv.beamform_cap);
-
- for (i = 0; i < 16; i++) {
- preorder_ctrl = &psta->recvreorder_ctrl[i];
- if (preorder_ctrl->enable) {
- DBG_871X_SEL_NL(m, "tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq);
- }
- }
-
- } else {
- DBG_871X_SEL_NL(m, "can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress));
- }
-
- return 0;
-}
-
-int proc_get_adapter_state(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- DBG_871X_SEL_NL(m, "name =%s, bSurpriseRemoved =%d, bDriverStopped =%d\n",
- dev->name, padapter->bSurpriseRemoved, padapter->bDriverStopped);
-
- return 0;
-}
-
-int proc_get_trx_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- int i;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
- struct recv_priv *precvpriv = &padapter->recvpriv;
- struct hw_xmit *phwxmit;
-
- DBG_871X_SEL_NL(m, "free_xmitbuf_cnt =%d, free_xmitframe_cnt =%d\n"
- , pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt);
- DBG_871X_SEL_NL(m, "free_ext_xmitbuf_cnt =%d, free_xframe_ext_cnt =%d\n"
- , pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xframe_ext_cnt);
- DBG_871X_SEL_NL(m, "free_recvframe_cnt =%d\n"
- , precvpriv->free_recvframe_cnt);
-
- for (i = 0; i < 4; i++) {
- phwxmit = pxmitpriv->hwxmits + i;
- DBG_871X_SEL_NL(m, "%d, hwq.accnt =%d\n", i, phwxmit->accnt);
- }
-
- return 0;
-}
-
-int proc_get_rate_ctl(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- if (adapter->fix_rate != 0xff) {
- DBG_871X_SEL_NL(m, "FIX\n");
- DBG_871X_SEL_NL(m, "0x%02x\n", adapter->fix_rate);
- } else {
- DBG_871X_SEL_NL(m, "RA\n");
- }
-
- return 0;
-}
-
-ssize_t proc_set_rate_ctl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
- char tmp[32];
- u8 fix_rate;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%hhx", &fix_rate);
-
- if (num >= 1)
- adapter->fix_rate = fix_rate;
- }
-
- return count;
-}
-
-ssize_t proc_set_fwdl_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- char tmp[32];
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- sscanf(tmp, "%hhu %hhu", &g_fwdl_chksum_fail, &g_fwdl_wintint_rdy_fail);
- }
-
- return count;
-}
-
-ssize_t proc_set_wait_hiq_empty(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- char tmp[32];
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- sscanf(tmp, "%u", &g_wait_hiq_empty);
- }
-
- return count;
-}
-
-int proc_get_suspend_resume_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct dvobj_priv *dvobj = padapter->dvobj;
- struct debug_priv *pdbgpriv = &dvobj->drv_dbg;
-
- DBG_871X_SEL_NL(m, "dbg_sdio_alloc_irq_cnt =%d\n", pdbgpriv->dbg_sdio_alloc_irq_cnt);
- DBG_871X_SEL_NL(m, "dbg_sdio_free_irq_cnt =%d\n", pdbgpriv->dbg_sdio_free_irq_cnt);
- DBG_871X_SEL_NL(m, "dbg_sdio_alloc_irq_error_cnt =%d\n", pdbgpriv->dbg_sdio_alloc_irq_error_cnt);
- DBG_871X_SEL_NL(m, "dbg_sdio_free_irq_error_cnt =%d\n", pdbgpriv->dbg_sdio_free_irq_error_cnt);
- DBG_871X_SEL_NL(m, "dbg_sdio_init_error_cnt =%d\n", pdbgpriv->dbg_sdio_init_error_cnt);
- DBG_871X_SEL_NL(m, "dbg_sdio_deinit_error_cnt =%d\n", pdbgpriv->dbg_sdio_deinit_error_cnt);
- DBG_871X_SEL_NL(m, "dbg_suspend_error_cnt =%d\n", pdbgpriv->dbg_suspend_error_cnt);
- DBG_871X_SEL_NL(m, "dbg_suspend_cnt =%d\n", pdbgpriv->dbg_suspend_cnt);
- DBG_871X_SEL_NL(m, "dbg_resume_cnt =%d\n", pdbgpriv->dbg_resume_cnt);
- DBG_871X_SEL_NL(m, "dbg_resume_error_cnt =%d\n", pdbgpriv->dbg_resume_error_cnt);
- DBG_871X_SEL_NL(m, "dbg_deinit_fail_cnt =%d\n", pdbgpriv->dbg_deinit_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_carddisable_cnt =%d\n", pdbgpriv->dbg_carddisable_cnt);
- DBG_871X_SEL_NL(m, "dbg_ps_insuspend_cnt =%d\n", pdbgpriv->dbg_ps_insuspend_cnt);
- DBG_871X_SEL_NL(m, "dbg_dev_unload_inIPS_cnt =%d\n", pdbgpriv->dbg_dev_unload_inIPS_cnt);
- DBG_871X_SEL_NL(m, "dbg_scan_pwr_state_cnt =%d\n", pdbgpriv->dbg_scan_pwr_state_cnt);
- DBG_871X_SEL_NL(m, "dbg_downloadfw_pwr_state_cnt =%d\n", pdbgpriv->dbg_downloadfw_pwr_state_cnt);
- DBG_871X_SEL_NL(m, "dbg_carddisable_error_cnt =%d\n", pdbgpriv->dbg_carddisable_error_cnt);
- DBG_871X_SEL_NL(m, "dbg_fw_read_ps_state_fail_cnt =%d\n", pdbgpriv->dbg_fw_read_ps_state_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_leave_ips_fail_cnt =%d\n", pdbgpriv->dbg_leave_ips_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_leave_lps_fail_cnt =%d\n", pdbgpriv->dbg_leave_lps_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_h2c_leave32k_fail_cnt =%d\n", pdbgpriv->dbg_h2c_leave32k_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_diswow_dload_fw_fail_cnt =%d\n", pdbgpriv->dbg_diswow_dload_fw_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_enwow_dload_fw_fail_cnt =%d\n", pdbgpriv->dbg_enwow_dload_fw_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_ips_drvopen_fail_cnt =%d\n", pdbgpriv->dbg_ips_drvopen_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_poll_fail_cnt =%d\n", pdbgpriv->dbg_poll_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_rpwm_toggle_cnt =%d\n", pdbgpriv->dbg_rpwm_toggle_cnt);
- DBG_871X_SEL_NL(m, "dbg_rpwm_timeout_fail_cnt =%d\n", pdbgpriv->dbg_rpwm_timeout_fail_cnt);
-
- return 0;
-}
-
-#ifdef CONFIG_DBG_COUNTER
-
-int proc_get_rx_logs(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct rx_logs *rx_logs = &padapter->rx_logs;
-
- DBG_871X_SEL_NL(m,
- "intf_rx =%d\n"
- "intf_rx_err_recvframe =%d\n"
- "intf_rx_err_skb =%d\n"
- "intf_rx_report =%d\n"
- "core_rx =%d\n"
- "core_rx_pre =%d\n"
- "core_rx_pre_ver_err =%d\n"
- "core_rx_pre_mgmt =%d\n"
- "core_rx_pre_mgmt_err_80211w =%d\n"
- "core_rx_pre_mgmt_err =%d\n"
- "core_rx_pre_ctrl =%d\n"
- "core_rx_pre_ctrl_err =%d\n"
- "core_rx_pre_data =%d\n"
- "core_rx_pre_data_wapi_seq_err =%d\n"
- "core_rx_pre_data_wapi_key_err =%d\n"
- "core_rx_pre_data_handled =%d\n"
- "core_rx_pre_data_err =%d\n"
- "core_rx_pre_data_unknown =%d\n"
- "core_rx_pre_unknown =%d\n"
- "core_rx_enqueue =%d\n"
- "core_rx_dequeue =%d\n"
- "core_rx_post =%d\n"
- "core_rx_post_decrypt =%d\n"
- "core_rx_post_decrypt_wep =%d\n"
- "core_rx_post_decrypt_tkip =%d\n"
- "core_rx_post_decrypt_aes =%d\n"
- "core_rx_post_decrypt_wapi =%d\n"
- "core_rx_post_decrypt_hw =%d\n"
- "core_rx_post_decrypt_unknown =%d\n"
- "core_rx_post_decrypt_err =%d\n"
- "core_rx_post_defrag_err =%d\n"
- "core_rx_post_portctrl_err =%d\n"
- "core_rx_post_indicate =%d\n"
- "core_rx_post_indicate_in_oder =%d\n"
- "core_rx_post_indicate_reoder =%d\n"
- "core_rx_post_indicate_err =%d\n"
- "os_indicate =%d\n"
- "os_indicate_ap_mcast =%d\n"
- "os_indicate_ap_forward =%d\n"
- "os_indicate_ap_self =%d\n"
- "os_indicate_err =%d\n"
- "os_netif_ok =%d\n"
- "os_netif_err =%d\n",
- rx_logs->intf_rx,
- rx_logs->intf_rx_err_recvframe,
- rx_logs->intf_rx_err_skb,
- rx_logs->intf_rx_report,
- rx_logs->core_rx,
- rx_logs->core_rx_pre,
- rx_logs->core_rx_pre_ver_err,
- rx_logs->core_rx_pre_mgmt,
- rx_logs->core_rx_pre_mgmt_err_80211w,
- rx_logs->core_rx_pre_mgmt_err,
- rx_logs->core_rx_pre_ctrl,
- rx_logs->core_rx_pre_ctrl_err,
- rx_logs->core_rx_pre_data,
- rx_logs->core_rx_pre_data_wapi_seq_err,
- rx_logs->core_rx_pre_data_wapi_key_err,
- rx_logs->core_rx_pre_data_handled,
- rx_logs->core_rx_pre_data_err,
- rx_logs->core_rx_pre_data_unknown,
- rx_logs->core_rx_pre_unknown,
- rx_logs->core_rx_enqueue,
- rx_logs->core_rx_dequeue,
- rx_logs->core_rx_post,
- rx_logs->core_rx_post_decrypt,
- rx_logs->core_rx_post_decrypt_wep,
- rx_logs->core_rx_post_decrypt_tkip,
- rx_logs->core_rx_post_decrypt_aes,
- rx_logs->core_rx_post_decrypt_wapi,
- rx_logs->core_rx_post_decrypt_hw,
- rx_logs->core_rx_post_decrypt_unknown,
- rx_logs->core_rx_post_decrypt_err,
- rx_logs->core_rx_post_defrag_err,
- rx_logs->core_rx_post_portctrl_err,
- rx_logs->core_rx_post_indicate,
- rx_logs->core_rx_post_indicate_in_oder,
- rx_logs->core_rx_post_indicate_reoder,
- rx_logs->core_rx_post_indicate_err,
- rx_logs->os_indicate,
- rx_logs->os_indicate_ap_mcast,
- rx_logs->os_indicate_ap_forward,
- rx_logs->os_indicate_ap_self,
- rx_logs->os_indicate_err,
- rx_logs->os_netif_ok,
- rx_logs->os_netif_err
- );
-
- return 0;
-}
-
-int proc_get_tx_logs(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct tx_logs *tx_logs = &padapter->tx_logs;
-
- DBG_871X_SEL_NL(m,
- "os_tx =%d\n"
- "os_tx_err_up =%d\n"
- "os_tx_err_xmit =%d\n"
- "os_tx_m2u =%d\n"
- "os_tx_m2u_ignore_fw_linked =%d\n"
- "os_tx_m2u_ignore_self =%d\n"
- "os_tx_m2u_entry =%d\n"
- "os_tx_m2u_entry_err_xmit =%d\n"
- "os_tx_m2u_entry_err_skb =%d\n"
- "os_tx_m2u_stop =%d\n"
- "core_tx =%d\n"
- "core_tx_err_pxmitframe =%d\n"
- "core_tx_err_brtx =%d\n"
- "core_tx_upd_attrib =%d\n"
- "core_tx_upd_attrib_adhoc =%d\n"
- "core_tx_upd_attrib_sta =%d\n"
- "core_tx_upd_attrib_ap =%d\n"
- "core_tx_upd_attrib_unknown =%d\n"
- "core_tx_upd_attrib_dhcp =%d\n"
- "core_tx_upd_attrib_icmp =%d\n"
- "core_tx_upd_attrib_active =%d\n"
- "core_tx_upd_attrib_err_ucast_sta =%d\n"
- "core_tx_upd_attrib_err_ucast_ap_link =%d\n"
- "core_tx_upd_attrib_err_sta =%d\n"
- "core_tx_upd_attrib_err_link =%d\n"
- "core_tx_upd_attrib_err_sec =%d\n"
- "core_tx_ap_enqueue_warn_fwstate =%d\n"
- "core_tx_ap_enqueue_warn_sta =%d\n"
- "core_tx_ap_enqueue_warn_nosta =%d\n"
- "core_tx_ap_enqueue_warn_link =%d\n"
- "core_tx_ap_enqueue_warn_trigger =%d\n"
- "core_tx_ap_enqueue_mcast =%d\n"
- "core_tx_ap_enqueue_ucast =%d\n"
- "core_tx_ap_enqueue =%d\n"
- "intf_tx =%d\n"
- "intf_tx_pending_ac =%d\n"
- "intf_tx_pending_fw_under_survey =%d\n"
- "intf_tx_pending_fw_under_linking =%d\n"
- "intf_tx_pending_xmitbuf =%d\n"
- "intf_tx_enqueue =%d\n"
- "core_tx_enqueue =%d\n"
- "core_tx_enqueue_class =%d\n"
- "core_tx_enqueue_class_err_sta =%d\n"
- "core_tx_enqueue_class_err_nosta =%d\n"
- "core_tx_enqueue_class_err_fwlink =%d\n"
- "intf_tx_direct =%d\n"
- "intf_tx_direct_err_coalesce =%d\n"
- "intf_tx_dequeue =%d\n"
- "intf_tx_dequeue_err_coalesce =%d\n"
- "intf_tx_dump_xframe =%d\n"
- "intf_tx_dump_xframe_err_txdesc =%d\n"
- "intf_tx_dump_xframe_err_port =%d\n",
- tx_logs->os_tx,
- tx_logs->os_tx_err_up,
- tx_logs->os_tx_err_xmit,
- tx_logs->os_tx_m2u,
- tx_logs->os_tx_m2u_ignore_fw_linked,
- tx_logs->os_tx_m2u_ignore_self,
- tx_logs->os_tx_m2u_entry,
- tx_logs->os_tx_m2u_entry_err_xmit,
- tx_logs->os_tx_m2u_entry_err_skb,
- tx_logs->os_tx_m2u_stop,
- tx_logs->core_tx,
- tx_logs->core_tx_err_pxmitframe,
- tx_logs->core_tx_err_brtx,
- tx_logs->core_tx_upd_attrib,
- tx_logs->core_tx_upd_attrib_adhoc,
- tx_logs->core_tx_upd_attrib_sta,
- tx_logs->core_tx_upd_attrib_ap,
- tx_logs->core_tx_upd_attrib_unknown,
- tx_logs->core_tx_upd_attrib_dhcp,
- tx_logs->core_tx_upd_attrib_icmp,
- tx_logs->core_tx_upd_attrib_active,
- tx_logs->core_tx_upd_attrib_err_ucast_sta,
- tx_logs->core_tx_upd_attrib_err_ucast_ap_link,
- tx_logs->core_tx_upd_attrib_err_sta,
- tx_logs->core_tx_upd_attrib_err_link,
- tx_logs->core_tx_upd_attrib_err_sec,
- tx_logs->core_tx_ap_enqueue_warn_fwstate,
- tx_logs->core_tx_ap_enqueue_warn_sta,
- tx_logs->core_tx_ap_enqueue_warn_nosta,
- tx_logs->core_tx_ap_enqueue_warn_link,
- tx_logs->core_tx_ap_enqueue_warn_trigger,
- tx_logs->core_tx_ap_enqueue_mcast,
- tx_logs->core_tx_ap_enqueue_ucast,
- tx_logs->core_tx_ap_enqueue,
- tx_logs->intf_tx,
- tx_logs->intf_tx_pending_ac,
- tx_logs->intf_tx_pending_fw_under_survey,
- tx_logs->intf_tx_pending_fw_under_linking,
- tx_logs->intf_tx_pending_xmitbuf,
- tx_logs->intf_tx_enqueue,
- tx_logs->core_tx_enqueue,
- tx_logs->core_tx_enqueue_class,
- tx_logs->core_tx_enqueue_class_err_sta,
- tx_logs->core_tx_enqueue_class_err_nosta,
- tx_logs->core_tx_enqueue_class_err_fwlink,
- tx_logs->intf_tx_direct,
- tx_logs->intf_tx_direct_err_coalesce,
- tx_logs->intf_tx_dequeue,
- tx_logs->intf_tx_dequeue_err_coalesce,
- tx_logs->intf_tx_dump_xframe,
- tx_logs->intf_tx_dump_xframe_err_txdesc,
- tx_logs->intf_tx_dump_xframe_err_port
- );
-
- return 0;
-}
-
-int proc_get_int_logs(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- DBG_871X_SEL_NL(m,
- "all =%d\n"
- "err =%d\n"
- "tbdok =%d\n"
- "tbder =%d\n"
- "bcnderr =%d\n"
- "bcndma =%d\n"
- "bcndma_e =%d\n"
- "rx =%d\n"
- "rx_rdu =%d\n"
- "rx_fovw =%d\n"
- "txfovw =%d\n"
- "mgntok =%d\n"
- "highdok =%d\n"
- "bkdok =%d\n"
- "bedok =%d\n"
- "vidok =%d\n"
- "vodok =%d\n",
- padapter->int_logs.all,
- padapter->int_logs.err,
- padapter->int_logs.tbdok,
- padapter->int_logs.tbder,
- padapter->int_logs.bcnderr,
- padapter->int_logs.bcndma,
- padapter->int_logs.bcndma_e,
- padapter->int_logs.rx,
- padapter->int_logs.rx_rdu,
- padapter->int_logs.rx_fovw,
- padapter->int_logs.txfovw,
- padapter->int_logs.mgntok,
- padapter->int_logs.highdok,
- padapter->int_logs.bkdok,
- padapter->int_logs.bedok,
- padapter->int_logs.vidok,
- padapter->int_logs.vodok
- );
-
- return 0;
-}
-
-#endif /* CONFIG_DBG_COUNTER*/
-
-int proc_get_rx_signal(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- DBG_871X_SEL_NL(m, "rssi:%d\n", padapter->recvpriv.rssi);
- /*DBG_871X_SEL_NL(m, "rxpwdb:%d\n", padapter->recvpriv.rxpwdb);*/
- DBG_871X_SEL_NL(m, "signal_strength:%u\n", padapter->recvpriv.signal_strength);
- DBG_871X_SEL_NL(m, "signal_qual:%u\n", padapter->recvpriv.signal_qual);
- DBG_871X_SEL_NL(m, "noise:%d\n", padapter->recvpriv.noise);
- rtw_odm_get_perpkt_rssi(m, padapter);
- #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA
- rtw_get_raw_rssi_info(m, padapter);
- #endif
- return 0;
-}
-
-
-int proc_get_hw_status(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct dvobj_priv *dvobj = padapter->dvobj;
- struct debug_priv *pdbgpriv = &dvobj->drv_dbg;
-
- DBG_871X_SEL_NL(m, "RX FIFO full count: last_time =%lld, current_time =%lld, differential =%lld\n"
- , pdbgpriv->dbg_rx_fifo_last_overflow, pdbgpriv->dbg_rx_fifo_curr_overflow, pdbgpriv->dbg_rx_fifo_diff_overflow);
-
- return 0;
-}
-
-ssize_t proc_set_rx_signal(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- char tmp[32];
- u32 is_signal_dbg, signal_strength;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength);
-
- is_signal_dbg = is_signal_dbg == 0?0:1;
-
- if (is_signal_dbg && num != 2)
- return count;
-
- signal_strength = signal_strength > 100?100:signal_strength;
-
- padapter->recvpriv.is_signal_dbg = is_signal_dbg;
- padapter->recvpriv.signal_strength_dbg = signal_strength;
-
- if (is_signal_dbg)
- DBG_871X("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength);
- else
- DBG_871X("set %s\n", "HW_SIGNAL_STRENGTH");
-
- }
-
- return count;
-
-}
-
-int proc_get_ht_enable(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
-
- if (pregpriv)
- DBG_871X_SEL_NL(m, "%d\n", pregpriv->ht_enable);
-
- return 0;
-}
-
-ssize_t proc_set_ht_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
- char tmp[32];
- u32 mode;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- sscanf(tmp, "%d ", &mode);
-
- if (pregpriv && mode < 2) {
- pregpriv->ht_enable = mode;
- printk("ht_enable =%d\n", pregpriv->ht_enable);
- }
- }
-
- return count;
-
-}
-
-int proc_get_bw_mode(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
-
- if (pregpriv)
- DBG_871X_SEL_NL(m, "0x%02x\n", pregpriv->bw_mode);
-
- return 0;
-}
-
-ssize_t proc_set_bw_mode(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
- char tmp[32];
- u32 mode;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- sscanf(tmp, "%d ", &mode);
-
- if (pregpriv && mode < 2) {
-
- pregpriv->bw_mode = mode;
- printk("bw_mode =%d\n", mode);
-
- }
- }
-
- return count;
-
-}
-
-int proc_get_ampdu_enable(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
-
- if (pregpriv)
- DBG_871X_SEL_NL(m, "%d\n", pregpriv->ampdu_enable);
-
- return 0;
-}
-
-ssize_t proc_set_ampdu_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
- char tmp[32];
- u32 mode;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- sscanf(tmp, "%d ", &mode);
-
- if (pregpriv && mode < 3) {
- pregpriv->ampdu_enable = mode;
- printk("ampdu_enable =%d\n", mode);
- }
-
- }
-
- return count;
-
-}
-
-int proc_get_rx_ampdu(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-
- if (pregpriv)
- DBG_871X_SEL_NL(m,
- "accept_addba_req = %d , 0:Reject AP's Add BA req, 1:Accept AP's Add BA req.\n",
- pmlmeinfo->accept_addba_req
- );
-
- return 0;
-}
-
-ssize_t proc_set_rx_ampdu(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- char tmp[32];
- u32 mode;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- sscanf(tmp, "%d ", &mode);
-
- if (pregpriv && mode < 2) {
- pmlmeinfo->accept_addba_req = mode;
- DBG_871X("pmlmeinfo->accept_addba_req =%d\n",
- pmlmeinfo->accept_addba_req);
- if (mode == 0) {
- /*tear down Rx AMPDU*/
- send_delba(padapter, 0, get_my_bssid(&(pmlmeinfo->network)));/* recipient*/
- }
- }
-
- }
-
- return count;
-}
-
-int proc_get_en_fwps(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
-
- if (pregpriv)
- DBG_871X_SEL_NL(m, "check_fw_ps = %d , 1:enable get FW PS state , 0: disable get FW PS state\n"
- , pregpriv->check_fw_ps);
-
- return 0;
-}
-
-ssize_t proc_set_en_fwps(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
- char tmp[32];
- u32 mode;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- sscanf(tmp, "%d ", &mode);
-
- if (pregpriv && mode < 2) {
- pregpriv->check_fw_ps = mode;
- DBG_871X("pregpriv->check_fw_ps =%d\n", pregpriv->check_fw_ps);
- }
- }
- return count;
-}
-
-int proc_get_rx_stbc(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
-
- if (pregpriv)
- DBG_871X_SEL_NL(m, "%d\n", pregpriv->rx_stbc);
-
- return 0;
-}
-
-ssize_t proc_set_rx_stbc(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct registry_priv *pregpriv = &padapter->registrypriv;
- char tmp[32];
- u32 mode;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- sscanf(tmp, "%d ", &mode);
-
- if (pregpriv && (mode == 0 || mode == 1 ||
- mode == 2 || mode == 3)) {
- pregpriv->rx_stbc = mode;
- printk("rx_stbc =%d\n", mode);
- }
- }
-
- return count;
-
-}
-
-int proc_get_rssi_disp(struct seq_file *m, void *v)
-{
- return 0;
-}
-
-ssize_t proc_set_rssi_disp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- char tmp[32];
- u32 enable = 0;
-
- if (count < 1) {
- DBG_8192C("argument size is less than 1\n");
- return -EFAULT;
- }
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- int num = sscanf(tmp, "%x", &enable);
-
- if (num != 1) {
- DBG_8192C("invalid set_rssi_disp parameter!\n");
- return count;
- }
-
- if (enable) {
- DBG_8192C("Linked info Function Enable\n");
- padapter->bLinkInfoDump = enable;
- } else {
- DBG_8192C("Linked info Function Disable\n");
- padapter->bLinkInfoDump = 0;
- }
- }
- return count;
-}
-
-int proc_get_all_sta_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct sta_info *psta;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct sta_priv *pstapriv = &padapter->stapriv;
- int i, j;
- struct list_head *plist, *phead;
- struct recv_reorder_ctrl *preorder_ctrl;
-
- DBG_871X_SEL_NL(m, "sta_dz_bitmap = 0x%x, tim_bitmap = 0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap);
-
- spin_lock_bh(&pstapriv->sta_hash_lock);
-
- for (i = 0; i < NUM_STA; i++) {
- phead = &(pstapriv->sta_hash[i]);
- plist = get_next(phead);
-
- while (phead != plist) {
- psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
-
- plist = get_next(plist);
-
- DBG_871X_SEL_NL(m, "==============================\n");
- DBG_871X_SEL_NL(m, "sta's macaddr:" MAC_FMT "\n",
- MAC_ARG(psta->hwaddr));
- DBG_871X_SEL_NL(m, "rtsen =%d, cts2slef =%d\n",
- psta->rtsen, psta->cts2self);
- DBG_871X_SEL_NL(m, "state = 0x%x, aid =%d, macid =%d, raid =%d\n",
- psta->state, psta->aid, psta->mac_id,
- psta->raid);
- DBG_871X_SEL_NL(m, "qos_en =%d, ht_en =%d, init_rate =%d\n",
- psta->qos_option,
- psta->htpriv.ht_option,
- psta->init_rate);
- DBG_871X_SEL_NL(m, "bwmode =%d, ch_offset =%d, sgi_20m =%d, sgi_40m =%d\n",
- psta->bw_mode, psta->htpriv.ch_offset,
- psta->htpriv.sgi_20m,
- psta->htpriv.sgi_40m);
- DBG_871X_SEL_NL(m, "ampdu_enable = %d\n",
- psta->htpriv.ampdu_enable);
- DBG_871X_SEL_NL(m, "agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n",
- psta->htpriv.agg_enable_bitmap,
- psta->htpriv.candidate_tid_bitmap);
- DBG_871X_SEL_NL(m, "sleepq_len =%d\n",
- psta->sleepq_len);
- DBG_871X_SEL_NL(m, "sta_xmitpriv.vo_q_qcnt =%d\n",
- psta->sta_xmitpriv.vo_q.qcnt);
- DBG_871X_SEL_NL(m, "sta_xmitpriv.vi_q_qcnt =%d\n",
- psta->sta_xmitpriv.vi_q.qcnt);
- DBG_871X_SEL_NL(m, "sta_xmitpriv.be_q_qcnt =%d\n",
- psta->sta_xmitpriv.be_q.qcnt);
- DBG_871X_SEL_NL(m, "sta_xmitpriv.bk_q_qcnt =%d\n",
- psta->sta_xmitpriv.bk_q.qcnt);
-
- DBG_871X_SEL_NL(m, "capability = 0x%x\n",
- psta->capability);
- DBG_871X_SEL_NL(m, "flags = 0x%x\n", psta->flags);
- DBG_871X_SEL_NL(m, "wpa_psk = 0x%x\n", psta->wpa_psk);
- DBG_871X_SEL_NL(m, "wpa2_group_cipher = 0x%x\n",
- psta->wpa2_group_cipher);
- DBG_871X_SEL_NL(m, "wpa2_pairwise_cipher = 0x%x\n",
- psta->wpa2_pairwise_cipher);
- DBG_871X_SEL_NL(m, "qos_info = 0x%x\n", psta->qos_info);
- DBG_871X_SEL_NL(m, "dot118021XPrivacy = 0x%x\n",
- psta->dot118021XPrivacy);
-
- for (j = 0; j < 16; j++) {
- preorder_ctrl = &psta->recvreorder_ctrl[j];
- if (preorder_ctrl->enable)
- DBG_871X_SEL_NL(m, "tid =%d, indicate_seq =%d\n",
- j, preorder_ctrl->indicate_seq);
- }
- DBG_871X_SEL_NL(m, "==============================\n");
- }
- }
-
- spin_unlock_bh(&pstapriv->sta_hash_lock);
-
- return 0;
-}
-
-int proc_get_btcoex_dbg(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter;
- char buf[512] = {0};
- padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- hal_btcoex_GetDBG(padapter, buf, 512);
-
- DBG_871X_SEL(m, "%s", buf);
-
- return 0;
-}
-
-ssize_t proc_set_btcoex_dbg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter;
- u8 tmp[80] = {0};
- u32 module[2] = {0};
- u32 num;
-
- padapter = (struct adapter *)rtw_netdev_priv(dev);
-
-/* DBG_871X("+" FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter));*/
-
- if (NULL == buffer) {
- DBG_871X(FUNC_ADPT_FMT ": input buffer is NULL!\n",
- FUNC_ADPT_ARG(padapter));
-
- return -EFAULT;
- }
-
- if (count < 1) {
- DBG_871X(FUNC_ADPT_FMT ": input length is 0!\n",
- FUNC_ADPT_ARG(padapter));
-
- return -EFAULT;
- }
-
- num = count;
- if (num > (sizeof(tmp) - 1))
- num = (sizeof(tmp) - 1);
-
- if (copy_from_user(tmp, buffer, num)) {
- DBG_871X(FUNC_ADPT_FMT ": copy buffer from user space FAIL!\n",
- FUNC_ADPT_ARG(padapter));
-
- return -EFAULT;
- }
-
- num = sscanf(tmp, "%x %x", module, module+1);
- if (num == 1) {
- if (module[0] == 0)
- memset(module, 0, sizeof(module));
- else
- memset(module, 0xFF, sizeof(module));
- } else if (num != 2) {
- DBG_871X(FUNC_ADPT_FMT ": input(\"%s\") format incorrect!\n",
- FUNC_ADPT_ARG(padapter), tmp);
-
- if (num == 0)
- return -EFAULT;
- }
-
- DBG_871X(FUNC_ADPT_FMT ": input 0x%08X 0x%08X\n",
- FUNC_ADPT_ARG(padapter), module[0], module[1]);
- hal_btcoex_SetDBG(padapter, module);
-
- return count;
-}
-
-int proc_get_btcoex_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter;
- const u32 bufsize = 30*100;
- u8 *pbuf = NULL;
-
- padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- pbuf = rtw_zmalloc(bufsize);
- if (!pbuf)
- return -ENOMEM;
-
- hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
-
- DBG_871X_SEL(m, "%s\n", pbuf);
-
- kfree(pbuf);
-
- return 0;
-}
-
-#endif
diff --git a/drivers/staging/rtl8723bs/core/rtw_io.c b/drivers/staging/rtl8723bs/core/rtw_io.c
index a92bc19b196a..57168578663a 100644
--- a/drivers/staging/rtl8723bs/core/rtw_io.c
+++ b/drivers/staging/rtl8723bs/core/rtw_io.c
@@ -142,7 +142,7 @@ u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &(pio_priv->intf);
- u32 ret = _SUCCESS;
+ u32 ret;
_write_port = pintfhdl->io_ops._write_port;
diff --git a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c
index 8eb0ff57925f..eb08569db5ea 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c
@@ -9,13 +9,6 @@
#include <drv_types.h>
#include <rtw_debug.h>
-#define IS_MAC_ADDRESS_BROADCAST(addr) \
-(\
- ((addr[0] == 0xff) && (addr[1] == 0xff) && \
- (addr[2] == 0xff) && (addr[3] == 0xff) && \
- (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \
-)
-
u8 rtw_validate_bssid(u8 *bssid)
{
u8 ret = true;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 4285844420cb..2128886c9924 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -295,11 +295,7 @@ static void init_mlme_ext_priv_value(struct adapter *padapter)
init_mlme_default_rate_set(padapter);
- if (pmlmeext->cur_channel > 14)
- pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB;
- else
- pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB;
-
+ pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB;
pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
pmlmeext->sitesurvey_res.channel_idx = 0;
pmlmeext->sitesurvey_res.bss_cnt = 0;
@@ -459,9 +455,8 @@ static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, RT_CHANNEL_
return chanset_size;
}
-int init_mlme_ext_priv(struct adapter *padapter)
+void init_mlme_ext_priv(struct adapter *padapter)
{
- int res = _SUCCESS;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -488,9 +483,6 @@ int init_mlme_ext_priv(struct adapter *padapter)
#ifdef DBG_FIXED_CHAN
pmlmeext->fixed_chan = 0xFF;
#endif
-
- return res;
-
}
void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext)
@@ -1882,7 +1874,6 @@ unsigned int OnAtim(struct adapter *padapter, union recv_frame *precv_frame)
unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_frame)
{
- unsigned int ret = _FAIL;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
u8 *pframe = precv_frame->u.hdr.rx_data;
@@ -1914,7 +1905,7 @@ unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_fr
}
exit:
- return ret;
+ return _FAIL;
}
unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_frame)
diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
index ae7fb7046c93..4075de07e0a9 100644
--- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
@@ -103,7 +103,7 @@ static bool rtw_pwr_unassociated_idle(struct adapter *adapter)
bool ret = false;
- if (adapter_to_pwrctl(adapter)->bpower_saving == true) {
+ if (adapter_to_pwrctl(adapter)->bpower_saving) {
/* DBG_871X("%s: already in LPS or IPS mode\n", __func__); */
goto exit;
}
@@ -167,7 +167,7 @@ void rtw_ps_processor(struct adapter *padapter)
goto exit;
}
- if (pwrpriv->bInSuspend == true) {/* system suspend or autosuspend */
+ if (pwrpriv->bInSuspend) {/* system suspend or autosuspend */
pdbgpriv->dbg_ps_insuspend_cnt++;
DBG_871X("%s, pwrpriv->bInSuspend == true ignore this process\n", __func__);
return;
@@ -219,10 +219,9 @@ void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets
if (jiffies_to_msecs(jiffies - start_time) > 2000) { /* 2 sec == watch dog timer */
if (xmit_cnt > 8) {
- if ((adapter_to_pwrctl(padapter)->bLeisurePs)
- && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
- && (hal_btcoex_IsBtControlLps(padapter) == false)
- ) {
+ if (adapter_to_pwrctl(padapter)->bLeisurePs
+ && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
+ && !(hal_btcoex_IsBtControlLps(padapter))) {
DBG_871X("leave lps via Tx = %d\n", xmit_cnt);
bLeaveLPS = true;
}
@@ -234,10 +233,9 @@ void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets
} else { /* from rx path */
if (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4/*2*/) {
- if ((adapter_to_pwrctl(padapter)->bLeisurePs)
- && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
- && (hal_btcoex_IsBtControlLps(padapter) == false)
- ) {
+ if (adapter_to_pwrctl(padapter)->bLeisurePs
+ && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
+ && !(hal_btcoex_IsBtControlLps(padapter))) {
DBG_871X("leave lps via Rx = %d\n", pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod);
bLeaveLPS = true;
}
@@ -267,7 +265,7 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
pslv = PS_STATE(pslv);
- if (pwrpriv->brpwmtimeout == true) {
+ if (pwrpriv->brpwmtimeout) {
DBG_871X("%s: RPWM timeout, force to set RPWM(0x%02X) again!\n", __func__, pslv);
} else {
if ((pwrpriv->rpwm == pslv)
@@ -278,8 +276,7 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
}
}
- if ((padapter->bSurpriseRemoved == true) ||
- (padapter->hw_init_completed == false)) {
+ if ((padapter->bSurpriseRemoved) || !(padapter->hw_init_completed)) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n",
__func__, padapter->bSurpriseRemoved, padapter->hw_init_completed));
@@ -289,7 +286,7 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
return;
}
- if (padapter->bDriverStopped == true) {
+ if (padapter->bDriverStopped) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv));
@@ -355,14 +352,14 @@ static u8 PS_RDY_CHECK(struct adapter *padapter)
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
- if (true == pwrpriv->bInSuspend && pwrpriv->wowlan_mode)
+ if (pwrpriv->bInSuspend && pwrpriv->wowlan_mode)
return true;
- else if (true == pwrpriv->bInSuspend && pwrpriv->wowlan_ap_mode)
+ else if (pwrpriv->bInSuspend && pwrpriv->wowlan_ap_mode)
return true;
- else if (true == pwrpriv->bInSuspend)
+ else if (pwrpriv->bInSuspend)
return false;
#else
- if (true == pwrpriv->bInSuspend)
+ if (pwrpriv->bInSuspend)
return false;
#endif
@@ -381,7 +378,7 @@ static u8 PS_RDY_CHECK(struct adapter *padapter)
)
return false;
- if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) {
+ if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && !(padapter->securitypriv.binstallGrpkey)) {
DBG_871X("Group handshake still in progress !!!\n");
return false;
}
@@ -417,13 +414,9 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
/* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */
if (ps_mode == PS_MODE_ACTIVE) {
- if (1
- && (((hal_btcoex_IsBtControlLps(padapter) == false)
- )
- || ((hal_btcoex_IsBtControlLps(padapter) == true)
- && (hal_btcoex_IsLpsOn(padapter) == false))
- )
- ) {
+ if (!(hal_btcoex_IsBtControlLps(padapter))
+ || (hal_btcoex_IsBtControlLps(padapter)
+ && !(hal_btcoex_IsLpsOn(padapter)))) {
DBG_871X(FUNC_ADPT_FMT" Leave 802.11 power save - %s\n",
FUNC_ADPT_ARG(padapter), msg);
@@ -431,8 +424,7 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
rtw_set_rpwm(padapter, PS_STATE_S4);
#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
- if (pwrpriv->wowlan_mode == true ||
- pwrpriv->wowlan_ap_mode == true) {
+ if (pwrpriv->wowlan_mode || pwrpriv->wowlan_ap_mode) {
unsigned long start_time;
u32 delay_ms;
u8 val8;
@@ -461,8 +453,8 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
}
} else {
if ((PS_RDY_CHECK(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE))
- || ((hal_btcoex_IsBtControlLps(padapter) == true)
- && (hal_btcoex_IsLpsOn(padapter) == true))
+ || ((hal_btcoex_IsBtControlLps(padapter))
+ && (hal_btcoex_IsLpsOn(padapter)))
) {
u8 pslv;
@@ -481,8 +473,8 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
if (pwrpriv->alives == 0)
pslv = PS_STATE_S0;
- if ((hal_btcoex_IsBtDisabled(padapter) == false)
- && (hal_btcoex_IsBtControlLps(padapter) == true)) {
+ if (!(hal_btcoex_IsBtDisabled(padapter))
+ && (hal_btcoex_IsBtControlLps(padapter))) {
u8 val8;
val8 = hal_btcoex_LpsVal(padapter);
@@ -513,10 +505,10 @@ s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms)
start_time = jiffies;
while (1) {
rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake);
- if (true == bAwake)
+ if (bAwake)
break;
- if (true == padapter->bSurpriseRemoved) {
+ if (padapter->bSurpriseRemoved) {
err = -2;
DBG_871X("%s: device surprise removed!!\n", __func__);
break;
@@ -544,7 +536,7 @@ void LPS_Enter(struct adapter *padapter, const char *msg)
int n_assoc_iface = 0;
char buf[32] = {0};
- if (hal_btcoex_IsBtControlLps(padapter) == true)
+ if (hal_btcoex_IsBtControlLps(padapter))
return;
/* Skip lps enter request if number of assocated adapters is not 1 */
@@ -557,8 +549,8 @@ void LPS_Enter(struct adapter *padapter, const char *msg)
if (get_iface_type(padapter) != IFACE_PORT0)
return;
- if (PS_RDY_CHECK(dvobj->padapters) == false)
- return;
+ if (!PS_RDY_CHECK(dvobj->padapters))
+ return;
if (pwrpriv->bLeisurePs) {
/* Idle for a while if we connect to AP a while ago. */
@@ -589,7 +581,7 @@ void LPS_Leave(struct adapter *padapter, const char *msg)
/* DBG_871X("+LeisurePSLeave\n"); */
- if (hal_btcoex_IsBtControlLps(padapter) == true)
+ if (hal_btcoex_IsBtControlLps(padapter))
return;
if (pwrpriv->bLeisurePs) {
@@ -615,13 +607,13 @@ void LeaveAllPowerSaveModeDirect(struct adapter *Adapter)
DBG_871X("%s.....\n", __func__);
- if (true == Adapter->bSurpriseRemoved) {
+ if (Adapter->bSurpriseRemoved) {
DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved =%d Skip!\n",
FUNC_ADPT_ARG(Adapter), Adapter->bSurpriseRemoved);
return;
}
- if ((check_fwstate(pmlmepriv, _FW_LINKED) == true)) { /* connect */
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */
if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) {
DBG_871X("%s: Driver Already Leave LPS\n", __func__);
@@ -637,7 +629,7 @@ void LeaveAllPowerSaveModeDirect(struct adapter *Adapter)
rtw_lps_ctrl_wk_cmd(pri_padapter, LPS_CTRL_LEAVE, 0);
} else {
if (pwrpriv->rf_pwrstate == rf_off)
- if (false == ips_leave(pri_padapter))
+ if (!ips_leave(pri_padapter))
DBG_871X("======> ips_leave fail.............\n");
}
}
@@ -675,7 +667,7 @@ void LeaveAllPowerSaveMode(struct adapter *Adapter)
LPS_Leave_check(Adapter);
} else {
if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) {
- if (false == ips_leave(Adapter))
+ if (!ips_leave(Adapter))
DBG_871X("======> ips_leave fail.............\n");
}
}
@@ -698,15 +690,14 @@ void LPS_Leave_check(
while (1) {
mutex_lock(&pwrpriv->lock);
- if ((padapter->bSurpriseRemoved == true)
- || (padapter->hw_init_completed == false)
- || (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
- )
+ if (padapter->bSurpriseRemoved
+ || !(padapter->hw_init_completed)
+ || (pwrpriv->pwr_mode == PS_MODE_ACTIVE))
bReady = true;
mutex_unlock(&pwrpriv->lock);
- if (true == bReady)
+ if (bReady)
break;
if (jiffies_to_msecs(jiffies - start_time) > 100) {
@@ -830,12 +821,12 @@ static void pwr_rpwm_timeout_handler(struct timer_list *t)
_set_workitem(&pwrpriv->rpwmtimeoutwi);
}
-static __inline void register_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag)
+static inline void register_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag)
{
pwrctrl->alives |= tag;
}
-static __inline void unregister_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag)
+static inline void unregister_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag)
{
pwrctrl->alives &= ~tag;
}
@@ -870,7 +861,7 @@ s32 rtw_register_task_alive(struct adapter *padapter, u32 task)
register_task_alive(pwrctrl, task);
- if (pwrctrl->bFwCurrentInPSMode == true) {
+ if (pwrctrl->bFwCurrentInPSMode) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
("%s: task = 0x%x cpwm = 0x%02x alives = 0x%08x\n",
__func__, task, pwrctrl->cpwm, pwrctrl->alives));
@@ -910,8 +901,8 @@ void rtw_unregister_task_alive(struct adapter *padapter, u32 task)
pwrctrl = adapter_to_pwrctl(padapter);
pslv = PS_STATE_S0;
- if ((hal_btcoex_IsBtDisabled(padapter) == false)
- && (hal_btcoex_IsBtControlLps(padapter) == true)) {
+ if (!(hal_btcoex_IsBtDisabled(padapter))
+ && hal_btcoex_IsBtControlLps(padapter)) {
u8 val8;
val8 = hal_btcoex_LpsVal(padapter);
@@ -924,7 +915,7 @@ void rtw_unregister_task_alive(struct adapter *padapter, u32 task)
unregister_task_alive(pwrctrl, task);
if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE)
- && (pwrctrl->bFwCurrentInPSMode == true)) {
+ && pwrctrl->bFwCurrentInPSMode) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
("%s: cpwm = 0x%02x alives = 0x%08x\n",
__func__, pwrctrl->cpwm, pwrctrl->alives));
@@ -965,7 +956,7 @@ s32 rtw_register_tx_alive(struct adapter *padapter)
register_task_alive(pwrctrl, XMIT_ALIVE);
- if (pwrctrl->bFwCurrentInPSMode == true) {
+ if (pwrctrl->bFwCurrentInPSMode) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
("rtw_register_tx_alive: cpwm = 0x%02x alives = 0x%08x\n",
pwrctrl->cpwm, pwrctrl->alives));
@@ -1014,7 +1005,7 @@ s32 rtw_register_cmd_alive(struct adapter *padapter)
register_task_alive(pwrctrl, CMD_ALIVE);
- if (pwrctrl->bFwCurrentInPSMode == true) {
+ if (pwrctrl->bFwCurrentInPSMode) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_,
("rtw_register_cmd_alive: cpwm = 0x%02x alives = 0x%08x\n",
pwrctrl->cpwm, pwrctrl->alives));
@@ -1051,8 +1042,8 @@ void rtw_unregister_tx_alive(struct adapter *padapter)
pwrctrl = adapter_to_pwrctl(padapter);
pslv = PS_STATE_S0;
- if ((hal_btcoex_IsBtDisabled(padapter) == false)
- && (hal_btcoex_IsBtControlLps(padapter) == true)) {
+ if (!(hal_btcoex_IsBtDisabled(padapter))
+ && hal_btcoex_IsBtControlLps(padapter)) {
u8 val8;
val8 = hal_btcoex_LpsVal(padapter);
@@ -1065,7 +1056,7 @@ void rtw_unregister_tx_alive(struct adapter *padapter)
unregister_task_alive(pwrctrl, XMIT_ALIVE);
if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE)
- && (pwrctrl->bFwCurrentInPSMode == true)) {
+ && pwrctrl->bFwCurrentInPSMode) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
("%s: cpwm = 0x%02x alives = 0x%08x\n",
__func__, pwrctrl->cpwm, pwrctrl->alives));
@@ -1093,8 +1084,8 @@ void rtw_unregister_cmd_alive(struct adapter *padapter)
pwrctrl = adapter_to_pwrctl(padapter);
pslv = PS_STATE_S0;
- if ((hal_btcoex_IsBtDisabled(padapter) == false)
- && (hal_btcoex_IsBtControlLps(padapter) == true)) {
+ if (!(hal_btcoex_IsBtDisabled(padapter))
+ && hal_btcoex_IsBtControlLps(padapter)) {
u8 val8;
val8 = hal_btcoex_LpsVal(padapter);
@@ -1107,7 +1098,7 @@ void rtw_unregister_cmd_alive(struct adapter *padapter)
unregister_task_alive(pwrctrl, CMD_ALIVE);
if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE)
- && (pwrctrl->bFwCurrentInPSMode == true)) {
+ && pwrctrl->bFwCurrentInPSMode) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_,
("%s: cpwm = 0x%02x alives = 0x%08x\n",
__func__, pwrctrl->cpwm, pwrctrl->alives));
@@ -1237,7 +1228,7 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal
DBG_871X("%s wait ps_processing done\n", __func__);
}
- if (pwrpriv->bInternalAutoSuspend == false && pwrpriv->bInSuspend) {
+ if (!(pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) {
DBG_871X("%s wait bInSuspend...\n", __func__);
while (pwrpriv->bInSuspend
&& jiffies_to_msecs(jiffies - start) <= 3000
@@ -1251,19 +1242,19 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal
}
/* System suspend is not allowed to wakeup */
- if ((pwrpriv->bInternalAutoSuspend == false) && (true == pwrpriv->bInSuspend)) {
+ if (!(pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) {
ret = _FAIL;
goto exit;
}
/* block??? */
- if ((pwrpriv->bInternalAutoSuspend == true) && (padapter->net_closed == true)) {
+ if (pwrpriv->bInternalAutoSuspend && padapter->net_closed) {
ret = _FAIL;
goto exit;
}
/* I think this should be check in IPS, LPS, autosuspend functions... */
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
ret = _SUCCESS;
goto exit;
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c
index 979056c3d397..57cfe06d7d73 100644
--- a/drivers/staging/rtl8723bs/core/rtw_security.c
+++ b/drivers/staging/rtl8723bs/core/rtw_security.c
@@ -2290,8 +2290,7 @@ static void gf_mulx(u8 *pad)
static void aes_encrypt_deinit(void *ctx)
{
- memset(ctx, 0, AES_PRIV_SIZE);
- kfree(ctx);
+ kzfree(ctx);
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
index 76c50377f0fe..ea3ea2a6b314 100644
--- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
@@ -451,7 +451,7 @@ void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigne
mutex_unlock(&(adapter_to_dvobj(padapter)->setch_mutex));
}
-__inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork)
+inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork)
{
return pnetwork->MacAddress;
}
@@ -1996,11 +1996,6 @@ void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len)
}
}
-void beacon_timing_control(struct adapter *padapter)
-{
- rtw_hal_bcn_related_reg_setting(padapter);
-}
-
void rtw_alloc_macid(struct adapter *padapter, struct sta_info *psta)
{
int i;
diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
index 8e4caeeb4070..dd349c506da8 100644
--- a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
+++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
@@ -1758,7 +1758,6 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
static s32 up, dn, m, n, WaitCount;
s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */
u8 retryCount = 0, btInfoExt;
- bool bWifiBusy = false;
BTC_PRINT(
BTC_MSG_ALGORITHM,
@@ -1766,11 +1765,6 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
("[BTCoex], TdmaDurationAdjustForAcl()\n")
);
- if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifiStatus)
- bWifiBusy = true;
- else
- bWifiBusy = false;
-
if (
(BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) ||
(BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) ||
diff --git a/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h b/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h
index aad86570b59c..7150d54d49ab 100644
--- a/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h
+++ b/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h
@@ -532,7 +532,6 @@ typedef struct _BTC_COEXIST {
extern BTC_COEXIST GLBtCoexist;
-u8 EXhalbtcoutsrc_InitlizeVariables(void *Adapter);
void EXhalbtcoutsrc_PowerOnSetting(PBTC_COEXIST pBtCoexist);
void EXhalbtcoutsrc_InitHwConfig(PBTC_COEXIST pBtCoexist, u8 bWifiOnly);
void EXhalbtcoutsrc_InitCoexDm(PBTC_COEXIST pBtCoexist);
diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c
index 5257287b4f4d..6e4a1fcb8790 100644
--- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c
+++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c
@@ -389,7 +389,6 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf)
u8 *pu8;
s32 *pS4Tmp;
u32 *pU4Tmp;
- u8 *pU1Tmp;
u8 ret;
@@ -403,7 +402,6 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf)
pu8 = pOutBuf;
pS4Tmp = pOutBuf;
pU4Tmp = pOutBuf;
- pU1Tmp = pOutBuf;
ret = true;
switch (getType) {
@@ -484,10 +482,8 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf)
*pU4Tmp = BTC_WIFI_BW_LEGACY;
else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_20)
*pU4Tmp = BTC_WIFI_BW_HT20;
- else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40)
- *pU4Tmp = BTC_WIFI_BW_HT40;
else
- *pU4Tmp = BTC_WIFI_BW_HT40; /* todo */
+ *pU4Tmp = BTC_WIFI_BW_HT40;
break;
case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION:
@@ -516,32 +512,32 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf)
break;
case BTC_GET_U1_WIFI_DOT11_CHNL:
- *pU1Tmp = padapter->mlmeextpriv.cur_channel;
+ *pu8 = padapter->mlmeextpriv.cur_channel;
break;
case BTC_GET_U1_WIFI_CENTRAL_CHNL:
- *pU1Tmp = pHalData->CurrentChannel;
+ *pu8 = pHalData->CurrentChannel;
break;
case BTC_GET_U1_WIFI_HS_CHNL:
- *pU1Tmp = 0;
+ *pu8 = 0;
ret = false;
break;
case BTC_GET_U1_MAC_PHY_MODE:
- *pU1Tmp = BTC_SMSP;
+ *pu8 = BTC_SMSP;
/* *pU1Tmp = BTC_DMSP; */
/* *pU1Tmp = BTC_DMDP; */
/* *pU1Tmp = BTC_MP_UNKNOWN; */
break;
case BTC_GET_U1_AP_NUM:
- *pU1Tmp = halbtcoutsrc_GetWifiScanAPNum(padapter);
+ *pu8 = halbtcoutsrc_GetWifiScanAPNum(padapter);
break;
/* 1Ant =========== */
case BTC_GET_U1_LPS_MODE:
- *pU1Tmp = padapter->dvobj->pwrctl_priv.pwr_mode;
+ *pu8 = padapter->dvobj->pwrctl_priv.pwr_mode;
break;
default:
@@ -959,9 +955,13 @@ static u8 EXhalbtcoutsrc_BindBtCoexWithAdapter(void *padapter)
return true;
}
-u8 EXhalbtcoutsrc_InitlizeVariables(void *padapter)
+void hal_btcoex_Initialize(void *padapter)
{
- PBTC_COEXIST pBtCoexist = &GLBtCoexist;
+ PBTC_COEXIST pBtCoexist;
+
+ memset(&GLBtCoexist, 0, sizeof(GLBtCoexist));
+
+ pBtCoexist = &GLBtCoexist;
/* pBtCoexist->statistics.cntBind++; */
@@ -1001,8 +1001,6 @@ u8 EXhalbtcoutsrc_InitlizeVariables(void *padapter)
GLBtcWiFiInScanState = false;
GLBtcWiFiInIQKState = false;
-
- return true;
}
void EXhalbtcoutsrc_PowerOnSetting(PBTC_COEXIST pBtCoexist)
@@ -1337,7 +1335,7 @@ void hal_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist)
*true Enable BT co-exist mechanism
*false Disable BT co-exist mechanism
*/
-u8 hal_btcoex_IsBtExist(struct adapter *padapter)
+bool hal_btcoex_IsBtExist(struct adapter *padapter)
{
struct hal_com_data *pHalData;
@@ -1384,12 +1382,6 @@ void hal_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath)
EXhalbtcoutsrc_SetSingleAntPath(singleAntPath);
}
-u8 hal_btcoex_Initialize(struct adapter *padapter)
-{
- memset(&GLBtCoexist, 0, sizeof(GLBtCoexist));
- return EXhalbtcoutsrc_InitlizeVariables((void *)padapter);
-}
-
void hal_btcoex_PowerOnSetting(struct adapter *padapter)
{
EXhalbtcoutsrc_PowerOnSetting(&GLBtCoexist);
@@ -1477,9 +1469,9 @@ void hal_btcoex_SetManualControl(struct adapter *padapter, u8 bmanual)
GLBtCoexist.bManualControl = bmanual;
}
-u8 hal_btcoex_IsBtControlLps(struct adapter *padapter)
+bool hal_btcoex_IsBtControlLps(struct adapter *padapter)
{
- if (hal_btcoex_IsBtExist(padapter) == false)
+ if (!hal_btcoex_IsBtExist(padapter))
return false;
if (GLBtCoexist.btInfo.bBtDisabled)
@@ -1491,9 +1483,9 @@ u8 hal_btcoex_IsBtControlLps(struct adapter *padapter)
return false;
}
-u8 hal_btcoex_IsLpsOn(struct adapter *padapter)
+bool hal_btcoex_IsLpsOn(struct adapter *padapter)
{
- if (hal_btcoex_IsBtExist(padapter) == false)
+ if (!hal_btcoex_IsBtExist(padapter))
return false;
if (GLBtCoexist.btInfo.bBtDisabled)
diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c
index 638b12ae6ee9..eddd56abbb2d 100644
--- a/drivers/staging/rtl8723bs/hal/hal_com.c
+++ b/drivers/staging/rtl8723bs/hal/hal_com.c
@@ -152,10 +152,7 @@ bool HAL_IsLegalChannel(struct adapter *Adapter, u32 Channel)
{
bool bLegalChannel = true;
- if (Channel > 14) {
- bLegalChannel = false;
- DBG_871X("Channel > 14 but wireless_mode do not support 5G\n");
- } else if ((Channel <= 14) && (Channel >= 1)) {
+ if ((Channel <= 14) && (Channel >= 1)) {
if (IsSupported24G(Adapter->registrypriv.wireless_mode) == false) {
bLegalChannel = false;
DBG_871X("(Channel <= 14) && (Channel >= 1) but wireless_mode do not support 2.4G\n");
diff --git a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
index 336764464e7d..6539bee9b5ba 100644
--- a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
+++ b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
@@ -2040,24 +2040,6 @@ void PHY_SetTxPowerLimit(
}
}
-u8 PHY_GetTxPowerIndex(
- struct adapter *padapter,
- u8 RFPath,
- u8 Rate,
- enum CHANNEL_WIDTH BandWidth,
- u8 Channel
-)
-{
- return PHY_GetTxPowerIndex_8723B(padapter, RFPath, Rate, BandWidth, Channel);
-}
-
-void PHY_SetTxPowerIndex(
- struct adapter *padapter, u32 PowerIndex, u8 RFPath, u8 Rate
-)
-{
- PHY_SetTxPowerIndex_8723B(padapter, PowerIndex, RFPath, Rate);
-}
-
void Hal_ChannelPlanToRegulation(struct adapter *Adapter, u16 ChannelPlan)
{
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
diff --git a/drivers/staging/rtl8723bs/hal/hal_intf.c b/drivers/staging/rtl8723bs/hal/hal_intf.c
index acb25978a46c..7d8f21f32fb9 100644
--- a/drivers/staging/rtl8723bs/hal/hal_intf.c
+++ b/drivers/staging/rtl8723bs/hal/hal_intf.c
@@ -369,7 +369,7 @@ void rtw_hal_dm_watchdog_in_lps(struct adapter *padapter)
}
}
-void rtw_hal_bcn_related_reg_setting(struct adapter *padapter)
+void beacon_timing_control(struct adapter *padapter)
{
if (padapter->HalFunc.SetBeaconRelatedRegistersHandler)
padapter->HalFunc.SetBeaconRelatedRegistersHandler(padapter);
diff --git a/drivers/staging/rtl8723bs/hal/hal_phy.c b/drivers/staging/rtl8723bs/hal/hal_phy.c
deleted file mode 100644
index 24a9d8f783f0..000000000000
--- a/drivers/staging/rtl8723bs/hal/hal_phy.c
+++ /dev/null
@@ -1,157 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-#define _HAL_PHY_C_
-
-#include <drv_types.h>
-
-/* */
-/* ==> RF shadow Operation API Code Section!!! */
-/* */
-/*-----------------------------------------------------------------------------
- * Function: PHY_RFShadowRead
- * PHY_RFShadowWrite
- * PHY_RFShadowCompare
- * PHY_RFShadowRecorver
- * PHY_RFShadowCompareAll
- * PHY_RFShadowRecorverAll
- * PHY_RFShadowCompareFlagSet
- * PHY_RFShadowRecorverFlagSet
- *
- * Overview: When we set RF register, we must write shadow at first.
- * When we are running, we must compare shadow abd locate error addr.
- * Decide to recorver or not.
- *
- * Input: NONE
- *
- * Output: NONE
- *
- * Return: NONE
- *
- * Revised History:
- * When Who Remark
- * 11/20/2008 MHC Create Version 0.
- *
- *---------------------------------------------------------------------------*/
-u32 PHY_RFShadowRead(IN PADAPTER Adapter, IN u8 eRFPath, IN u32 Offset)
-{
- return RF_Shadow[eRFPath][Offset].Value;
-
-} /* PHY_RFShadowRead */
-
-
-void PHY_RFShadowWrite(
- IN PADAPTER Adapter, IN u8 eRFPath, IN u32 Offset, IN u32 Data
-)
-{
- RF_Shadow[eRFPath][Offset].Value = (Data & bRFRegOffsetMask);
- RF_Shadow[eRFPath][Offset].Driver_Write = true;
-
-} /* PHY_RFShadowWrite */
-
-
-bool PHY_RFShadowCompare(IN PADAPTER Adapter, IN u8 eRFPath, IN u32 Offset)
-{
- u32 reg;
- /* Check if we need to check the register */
- if (RF_Shadow[eRFPath][Offset].Compare == true) {
- reg = rtw_hal_read_rfreg(Adapter, eRFPath, Offset, bRFRegOffsetMask);
- /* Compare shadow and real rf register for 20bits!! */
- if (RF_Shadow[eRFPath][Offset].Value != reg) {
- /* Locate error position. */
- RF_Shadow[eRFPath][Offset].ErrorOrNot = true;
- /* RT_TRACE(COMP_INIT, DBG_LOUD, */
- /* PHY_RFShadowCompare RF-%d Addr%02lx Err = %05lx\n", */
- /* eRFPath, Offset, reg)); */
- }
- return RF_Shadow[eRFPath][Offset].ErrorOrNot;
- }
- return false;
-} /* PHY_RFShadowCompare */
-
-
-void PHY_RFShadowRecorver(IN PADAPTER Adapter, IN u8 eRFPath, IN u32 Offset)
-{
- /* Check if the address is error */
- if (RF_Shadow[eRFPath][Offset].ErrorOrNot == true) {
- /* Check if we need to recorver the register. */
- if (RF_Shadow[eRFPath][Offset].Recorver == true) {
- rtw_hal_write_rfreg(Adapter, eRFPath, Offset, bRFRegOffsetMask,
- RF_Shadow[eRFPath][Offset].Value);
- /* RT_TRACE(COMP_INIT, DBG_LOUD, */
- /* PHY_RFShadowRecorver RF-%d Addr%02lx=%05lx", */
- /* eRFPath, Offset, RF_Shadow[eRFPath][Offset].Value)); */
- }
- }
-
-} /* PHY_RFShadowRecorver */
-
-
-void PHY_RFShadowCompareAll(IN PADAPTER Adapter)
-{
- u8 eRFPath = 0;
- u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
-
- for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
- for (Offset = 0; Offset < maxReg; Offset++) {
- PHY_RFShadowCompare(Adapter, eRFPath, Offset);
- }
- }
-
-} /* PHY_RFShadowCompareAll */
-
-
-void PHY_RFShadowRecorverAll(IN PADAPTER Adapter)
-{
- u8 eRFPath = 0;
- u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
-
- for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
- for (Offset = 0; Offset < maxReg; Offset++) {
- PHY_RFShadowRecorver(Adapter, eRFPath, Offset);
- }
- }
-
-} /* PHY_RFShadowRecorverAll */
-
-
-void
-PHY_RFShadowCompareFlagSet(
- IN PADAPTER Adapter, IN u8 eRFPath, IN u32 Offset, IN u8 Type
-)
-{
- /* Set True or False!!! */
- RF_Shadow[eRFPath][Offset].Compare = Type;
-
-} /* PHY_RFShadowCompareFlagSet */
-
-
-void PHY_RFShadowRecorverFlagSet(
- IN PADAPTER Adapter, IN u8 eRFPath, IN u32 Offset, IN u8 Type
-)
-{
- /* Set True or False!!! */
- RF_Shadow[eRFPath][Offset].Recorver = Type;
-
-} /* PHY_RFShadowRecorverFlagSet */
-
-
-void PHY_RFShadowCompareFlagSetAll(IN PADAPTER Adapter)
-{
- u8 eRFPath = 0;
- u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
-
- for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
- for (Offset = 0; Offset < maxReg; Offset++) {
- /* 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! */
- if (Offset != 0x26 && Offset != 0x27)
- PHY_RFShadowCompareFlagSet(Adapter, eRFPath, Offset, false);
- else
- PHY_RFShadowCompareFlagSet(Adapter, eRFPath, Offset, true);
- }
- }
-
-} /* PHY_RFShadowCompareFlagSetAll */
diff --git a/drivers/staging/rtl8723bs/hal/odm.c b/drivers/staging/rtl8723bs/hal/odm.c
index e3f4307f3d20..aa6631ee4ea7 100644
--- a/drivers/staging/rtl8723bs/hal/odm.c
+++ b/drivers/staging/rtl8723bs/hal/odm.c
@@ -339,13 +339,9 @@ void ODM_TXPowerTrackingCheck(PDM_ODM_T pDM_Odm);
void odm_RateAdaptiveMaskInit(PDM_ODM_T pDM_Odm);
-void odm_TXPowerTrackingThermalMeterInit(PDM_ODM_T pDM_Odm);
-
void odm_TXPowerTrackingInit(PDM_ODM_T pDM_Odm);
-void odm_TXPowerTrackingCheckCE(PDM_ODM_T pDM_Odm);
-
/* Remove Edca by Yu Chen */
@@ -1259,13 +1255,11 @@ void odm_RSSIMonitorCheckCE(PDM_ODM_T pDM_Odm)
int tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff;
u8 sta_cnt = 0;
u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */
- bool FirstConnect = false;
pRA_T pRA_Table = &pDM_Odm->DM_RA_Table;
if (pDM_Odm->bLinked != true)
return;
- FirstConnect = (pDM_Odm->bLinked) && (pRA_Table->firstconnect == false);
pRA_Table->firstconnect = pDM_Odm->bLinked;
/* if (check_fwstate(&Adapter->mlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true) */
@@ -1324,11 +1318,6 @@ void odm_RSSIMonitorCheckCE(PDM_ODM_T pDM_Odm)
/* 3 Tx Power Tracking */
/* 3 ============================================================ */
-void odm_TXPowerTrackingInit(PDM_ODM_T pDM_Odm)
-{
- odm_TXPowerTrackingThermalMeterInit(pDM_Odm);
-}
-
static u8 getSwingIndex(PDM_ODM_T pDM_Odm)
{
struct adapter *Adapter = pDM_Odm->Adapter;
@@ -1353,7 +1342,7 @@ static u8 getSwingIndex(PDM_ODM_T pDM_Odm)
return i;
}
-void odm_TXPowerTrackingThermalMeterInit(PDM_ODM_T pDM_Odm)
+void odm_TXPowerTrackingInit(PDM_ODM_T pDM_Odm)
{
u8 defaultSwingIndex = getSwingIndex(pDM_Odm);
u8 p = 0;
@@ -1397,14 +1386,8 @@ void odm_TXPowerTrackingThermalMeterInit(PDM_ODM_T pDM_Odm)
}
-
void ODM_TXPowerTrackingCheck(PDM_ODM_T pDM_Odm)
{
- odm_TXPowerTrackingCheckCE(pDM_Odm);
-}
-
-void odm_TXPowerTrackingCheckCE(PDM_ODM_T pDM_Odm)
-{
struct adapter *Adapter = pDM_Odm->Adapter;
if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK))
diff --git a/drivers/staging/rtl8723bs/hal/odm.h b/drivers/staging/rtl8723bs/hal/odm.h
index 6ba77bb70889..fba3b9e1491b 100644
--- a/drivers/staging/rtl8723bs/hal/odm.h
+++ b/drivers/staging/rtl8723bs/hal/odm.h
@@ -1365,10 +1365,6 @@ extern u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE];
#define SWAW_STEP_PEAK 0
#define SWAW_STEP_DETERMINE 1
-/* Remove DIG by yuchen */
-
-void ODM_SetAntenna(PDM_ODM_T pDM_Odm, u8 Antenna);
-
/* Remove BB power saving by Yuchen */
#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck
diff --git a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
index a73304639226..95edd148ac24 100644
--- a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
+++ b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
@@ -11,11 +11,6 @@ static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
- bool bEEPROMCheck;
- struct adapter *Adapter = pDM_Odm->Adapter;
- struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
-
- bEEPROMCheck = pHalData->EEPROMVersion >= 0x01;
if (pCfoTrack->CrystalCap == CrystalCap)
return;
diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
index 49fa814068b8..71919a3d81ab 100644
--- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
+++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
@@ -89,7 +89,6 @@ static void odm_RxPhyStatus92CSeries_Parsing(
u8 RSSI, total_rssi = 0;
bool isCCKrate = false;
u8 rf_rx_num = 0;
- u8 cck_highpwr = 0;
u8 LNA_idx, VGA_idx;
PPHY_STATUS_RPT_8192CD_T pPhyStaRpt = (PPHY_STATUS_RPT_8192CD_T)pPhyStatus;
@@ -107,16 +106,10 @@ static void odm_RxPhyStatus92CSeries_Parsing(
/* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
/* */
- /* if (pHalData->eRFPowerState == eRfOn) */
- cck_highpwr = pDM_Odm->bCckHighPower;
- /* else */
- /* cck_highpwr = false; */
-
cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ;
/* 2011.11.28 LukeLee: 88E use different LNA & VGA gain table */
/* The RSSI formula should be modified according to the gain table */
- /* In 88E, cck_highpwr is always set to 1 */
LNA_idx = ((cck_agc_rpt & 0xE0)>>5);
VGA_idx = (cck_agc_rpt & 0x1F);
rx_pwr_all = odm_CCKRSSI_8723B(LNA_idx, VGA_idx);
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
index 080e974914b6..7760fd0eb6c9 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
@@ -1300,7 +1300,7 @@ static void rtl8723b_set_FwScanOffloadInfo_cmd(struct adapter *padapter, PRSVDPA
}
#endif /* CONFIG_PNO_SUPPORT */
-static void rtl8723b_set_FwWoWlanRelated_cmd(struct adapter *padapter, u8 enable)
+void rtl8723b_set_wowlan_cmd(struct adapter *padapter, u8 enable)
{
struct security_priv *psecpriv = &padapter->securitypriv;
struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(padapter);
@@ -1346,11 +1346,6 @@ static void rtl8723b_set_FwWoWlanRelated_cmd(struct adapter *padapter, u8 enable
DBG_871X_LEVEL(_drv_always_, "-%s()-\n", __func__);
}
-
-void rtl8723b_set_wowlan_cmd(struct adapter *padapter, u8 enable)
-{
- rtl8723b_set_FwWoWlanRelated_cmd(padapter, enable);
-}
#endif /* CONFIG_WOWLAN */
#ifdef CONFIG_AP_WOWLAN
@@ -1398,7 +1393,7 @@ static void rtl8723b_set_Fw_AP_Offload_Cmd(struct adapter *padapter, u8 bFuncEn)
H2C_AP_OFFLOAD_LEN, u1H2CAPOffloadCtrlParm);
}
-static void rtl8723b_set_AP_FwWoWlan_cmd(struct adapter *padapter, u8 enable)
+void rtl8723b_set_ap_wowlan_cmd(struct adapter *padapter, u8 enable)
{
DBG_871X_LEVEL(_drv_always_, "+%s()+: enable =%d\n", __func__, enable);
if (enable) {
@@ -1411,12 +1406,6 @@ static void rtl8723b_set_AP_FwWoWlan_cmd(struct adapter *padapter, u8 enable)
rtl8723b_set_Fw_AP_Offload_Cmd(padapter, enable);
msleep(10);
DBG_871X_LEVEL(_drv_always_, "-%s()-\n", __func__);
- return ;
-}
-
-void rtl8723b_set_ap_wowlan_cmd(struct adapter *padapter, u8 enable)
-{
- rtl8723b_set_AP_FwWoWlan_cmd(padapter, enable);
}
#endif /* CONFIG_AP_WOWLAN */
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
index 25c75b977666..6df2b58bdc67 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
@@ -431,14 +431,12 @@ static int phy_BB8723b_Config_ParaFile(struct adapter *Adapter)
u8 sz8723BBRegFile[] = RTL8723B_PHY_REG;
u8 sz8723AGCTableFile[] = RTL8723B_AGC_TAB;
u8 sz8723BBBRegPgFile[] = RTL8723B_PHY_REG_PG;
- u8 sz8723BBRegMpFile[] = RTL8723B_PHY_REG_MP;
u8 sz8723BRFTxPwrLmtFile[] = RTL8723B_TXPWR_LMT;
- u8 *pszBBRegFile = NULL, *pszAGCTableFile = NULL, *pszBBRegPgFile = NULL, *pszBBRegMpFile = NULL, *pszRFTxPwrLmtFile = NULL;
+ u8 *pszBBRegFile = NULL, *pszAGCTableFile = NULL, *pszBBRegPgFile = NULL, *pszRFTxPwrLmtFile = NULL;
pszBBRegFile = sz8723BBRegFile;
pszAGCTableFile = sz8723AGCTableFile;
pszBBRegPgFile = sz8723BBBRegPgFile;
- pszBBRegMpFile = sz8723BBRegMpFile;
pszRFTxPwrLmtFile = sz8723BRFTxPwrLmtFile;
/* Read Tx Power Limit File */
@@ -585,7 +583,7 @@ int PHY_RFConfig8723B(struct adapter *Adapter)
* <20120830, Kordan>
**************************************************************************************************************/
-void PHY_SetTxPowerIndex_8723B(
+void PHY_SetTxPowerIndex(
struct adapter *Adapter,
u32 PowerIndex,
u8 RFPath,
@@ -668,7 +666,7 @@ void PHY_SetTxPowerIndex_8723B(
}
}
-u8 PHY_GetTxPowerIndex_8723B(
+u8 PHY_GetTxPowerIndex(
struct adapter *padapter,
u8 RFPath,
u8 Rate,
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
index e23b39ab16c5..0f3301091258 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
@@ -486,7 +486,6 @@ initbuferror:
}
if (precvpriv->pallocated_recv_buf) {
- n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
kfree(precvpriv->pallocated_recv_buf);
precvpriv->pallocated_recv_buf = NULL;
}
@@ -503,7 +502,7 @@ exit:
*/
void rtl8723bs_free_recv_priv(struct adapter *padapter)
{
- u32 i, n;
+ u32 i;
struct recv_priv *precvpriv;
struct recv_buf *precvbuf;
@@ -515,9 +514,8 @@ void rtl8723bs_free_recv_priv(struct adapter *padapter)
/* 3 2. free all recv buffers */
precvbuf = (struct recv_buf *)precvpriv->precv_buf;
if (precvbuf) {
- n = NR_RECVBUFF;
precvpriv->free_recv_buf_queue_cnt = 0;
- for (i = 0; i < n ; i++) {
+ for (i = 0; i < NR_RECVBUFF; i++) {
list_del_init(&precvbuf->list);
rtw_os_recvbuf_resource_free(padapter, precvbuf);
precvbuf++;
@@ -526,7 +524,6 @@ void rtl8723bs_free_recv_priv(struct adapter *padapter)
}
if (precvpriv->pallocated_recv_buf) {
- n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
kfree(precvpriv->pallocated_recv_buf);
precvpriv->pallocated_recv_buf = NULL;
}
diff --git a/drivers/staging/rtl8723bs/include/autoconf.h b/drivers/staging/rtl8723bs/include/autoconf.h
index 196aca3aed7b..8f4c1e734473 100644
--- a/drivers/staging/rtl8723bs/include/autoconf.h
+++ b/drivers/staging/rtl8723bs/include/autoconf.h
@@ -57,9 +57,5 @@
#define DBG 0 /* for ODM & BTCOEX debug */
#endif /* !DEBUG */
-#ifdef CONFIG_PROC_FS
-#define PROC_DEBUG
-#endif
-
/* define DBG_XMIT_BUF */
/* define DBG_XMIT_BUF_EXT */
diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h
index 96346ce064aa..8d7fce1e39b7 100644
--- a/drivers/staging/rtl8723bs/include/drv_types.h
+++ b/drivers/staging/rtl8723bs/include/drv_types.h
@@ -478,7 +478,7 @@ struct sdio_data intf_data;
#define dvobj_to_pwrctl(dvobj) (&(dvobj->pwrctl_priv))
#define pwrctl_to_dvobj(pwrctl) container_of(pwrctl, struct dvobj_priv, pwrctl_priv)
-__inline static struct device *dvobj_to_dev(struct dvobj_priv *dvobj)
+static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj)
{
/* todo: get interface type from dvobj and the return the dev accordingly */
#ifdef RTW_DVOBJ_CHIP_HW_TYPE
@@ -576,8 +576,6 @@ struct adapter {
int bup;
struct net_device_stats stats;
struct iw_statistics iwstats;
- struct proc_dir_entry *dir_dev;/* for proc directory */
- struct proc_dir_entry *dir_odm;
struct wireless_dev *rtw_wdev;
struct rtw_wdev_priv wdev_data;
@@ -636,14 +634,14 @@ struct adapter {
/* define RTW_DISABLE_FUNC(padapter, func) (atomic_add(&adapter_to_dvobj(padapter)->disable_func, (func))) */
/* define RTW_ENABLE_FUNC(padapter, func) (atomic_sub(&adapter_to_dvobj(padapter)->disable_func, (func))) */
-__inline static void RTW_DISABLE_FUNC(struct adapter *padapter, int func_bit)
+static inline void RTW_DISABLE_FUNC(struct adapter *padapter, int func_bit)
{
int df = atomic_read(&adapter_to_dvobj(padapter)->disable_func);
df |= func_bit;
atomic_set(&adapter_to_dvobj(padapter)->disable_func, df);
}
-__inline static void RTW_ENABLE_FUNC(struct adapter *padapter, int func_bit)
+static inline void RTW_ENABLE_FUNC(struct adapter *padapter, int func_bit)
{
int df = atomic_read(&adapter_to_dvobj(padapter)->disable_func);
df &= ~(func_bit);
diff --git a/drivers/staging/rtl8723bs/include/hal_btcoex.h b/drivers/staging/rtl8723bs/include/hal_btcoex.h
index 6f7514be998f..eb03813fdcb9 100644
--- a/drivers/staging/rtl8723bs/include/hal_btcoex.h
+++ b/drivers/staging/rtl8723bs/include/hal_btcoex.h
@@ -22,13 +22,13 @@ typedef struct _BT_COEXIST
void DBG_BT_INFO(u8 *dbgmsg);
void hal_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist);
-u8 hal_btcoex_IsBtExist(struct adapter *padapter);
+bool hal_btcoex_IsBtExist(struct adapter *padapter);
bool hal_btcoex_IsBtDisabled(struct adapter *);
void hal_btcoex_SetChipType(struct adapter *padapter, u8 chipType);
void hal_btcoex_SetPgAntNum(struct adapter *padapter, u8 antNum);
void hal_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath);
-u8 hal_btcoex_Initialize(struct adapter *padapter);
+void hal_btcoex_Initialize(void *padapter);
void hal_btcoex_PowerOnSetting(struct adapter *padapter);
void hal_btcoex_InitHwConfig(struct adapter *padapter, u8 bWifiOnly);
@@ -47,8 +47,8 @@ void hal_btcoex_Handler(struct adapter *padapter);
s32 hal_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *padapter);
void hal_btcoex_SetManualControl(struct adapter *padapter, u8 bmanual);
-u8 hal_btcoex_IsBtControlLps(struct adapter *);
-u8 hal_btcoex_IsLpsOn(struct adapter *);
+bool hal_btcoex_IsBtControlLps(struct adapter *padapter);
+bool hal_btcoex_IsLpsOn(struct adapter *padapter);
u8 hal_btcoex_RpwmVal(struct adapter *);
u8 hal_btcoex_LpsVal(struct adapter *);
u32 hal_btcoex_GetRaMask(struct adapter *);
diff --git a/drivers/staging/rtl8723bs/include/hal_com_phycfg.h b/drivers/staging/rtl8723bs/include/hal_com_phycfg.h
index f841546584a7..9167f1e7827f 100644
--- a/drivers/staging/rtl8723bs/include/hal_com_phycfg.h
+++ b/drivers/staging/rtl8723bs/include/hal_com_phycfg.h
@@ -213,23 +213,6 @@ PHY_GetTxPowerTrackingOffset(
u8 RFPath
);
-u8
-PHY_GetTxPowerIndex(
-struct adapter * padapter,
-u8 RFPath,
-u8 Rate,
-enum CHANNEL_WIDTH BandWidth,
-u8 Channel
- );
-
-void
-PHY_SetTxPowerIndex(
-struct adapter * padapter,
-u32 PowerIndex,
-u8 RFPath,
-u8 Rate
- );
-
void
Hal_ChannelPlanToRegulation(
struct adapter * Adapter,
diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h
index 3a0c3d079d50..24926ebaf950 100644
--- a/drivers/staging/rtl8723bs/include/hal_intf.h
+++ b/drivers/staging/rtl8723bs/include/hal_intf.h
@@ -362,7 +362,7 @@ void rtw_hal_add_ra_tid(struct adapter *padapter, u32 bitmap, u8 *arg, u8 rssi_l
void rtw_hal_start_thread(struct adapter *padapter);
void rtw_hal_stop_thread(struct adapter *padapter);
-void rtw_hal_bcn_related_reg_setting(struct adapter *padapter);
+void beacon_timing_control(struct adapter *padapter);
u32 rtw_hal_read_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask);
void rtw_hal_write_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data);
diff --git a/drivers/staging/rtl8723bs/include/hal_phy_cfg.h b/drivers/staging/rtl8723bs/include/hal_phy_cfg.h
index 640427f407e3..b40868b2e76f 100644
--- a/drivers/staging/rtl8723bs/include/hal_phy_cfg.h
+++ b/drivers/staging/rtl8723bs/include/hal_phy_cfg.h
@@ -65,7 +65,7 @@ int PHY_RFConfig8723B(struct adapter *Adapter );
s32 PHY_MACConfig8723B(struct adapter *padapter);
void
-PHY_SetTxPowerIndex_8723B(
+PHY_SetTxPowerIndex(
struct adapter * Adapter,
u32 PowerIndex,
u8 RFPath,
@@ -73,7 +73,7 @@ u8 Rate
);
u8
-PHY_GetTxPowerIndex_8723B(
+PHY_GetTxPowerIndex(
struct adapter * padapter,
u8 RFPath,
u8 Rate,
diff --git a/drivers/staging/rtl8723bs/include/osdep_intf.h b/drivers/staging/rtl8723bs/include/osdep_intf.h
index 40313d17a242..fa16139fcce6 100644
--- a/drivers/staging/rtl8723bs/include/osdep_intf.h
+++ b/drivers/staging/rtl8723bs/include/osdep_intf.h
@@ -64,8 +64,6 @@ u16 rtw_recv_select_queue(struct sk_buff *skb);
int rtw_ndev_notifier_register(void);
void rtw_ndev_notifier_unregister(void);
-#include "../os_dep/rtw_proc.h"
-
void rtw_ips_dev_unload(struct adapter *padapter);
int rtw_ips_pwr_up(struct adapter *padapter);
diff --git a/drivers/staging/rtl8723bs/include/osdep_service.h b/drivers/staging/rtl8723bs/include/osdep_service.h
index d2616af95ffa..81a9c19ecc6a 100644
--- a/drivers/staging/rtl8723bs/include/osdep_service.h
+++ b/drivers/staging/rtl8723bs/include/osdep_service.h
@@ -110,12 +110,12 @@ int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb);
extern void _rtw_init_queue(struct __queue *pqueue);
-static __inline void thread_enter(char *name)
+static inline void thread_enter(char *name)
{
allow_signal(SIGTERM);
}
-__inline static void flush_signals_thread(void)
+static inline void flush_signals_thread(void)
{
if (signal_pending (current))
{
@@ -125,7 +125,7 @@ __inline static void flush_signals_thread(void)
#define rtw_warn_on(condition) WARN_ON(condition)
-__inline static int rtw_bug_check(void *parg1, void *parg2, void *parg3, void *parg4)
+static inline int rtw_bug_check(void *parg1, void *parg2, void *parg3, void *parg4)
{
int ret = true;
@@ -136,7 +136,7 @@ __inline static int rtw_bug_check(void *parg1, void *parg2, void *parg3, void *p
#define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r))
#define RND4(x) (((x >> 2) + (((x & 3) == 0) ? 0: 1)) << 2)
-__inline static u32 _RND4(u32 sz)
+static inline u32 _RND4(u32 sz)
{
u32 val;
@@ -147,7 +147,7 @@ __inline static u32 _RND4(u32 sz)
}
-__inline static u32 _RND8(u32 sz)
+static inline u32 _RND8(u32 sz)
{
u32 val;
diff --git a/drivers/staging/rtl8723bs/include/osdep_service_linux.h b/drivers/staging/rtl8723bs/include/osdep_service_linux.h
index 2f1b51e614fb..c582ede1ac12 100644
--- a/drivers/staging/rtl8723bs/include/osdep_service_linux.h
+++ b/drivers/staging/rtl8723bs/include/osdep_service_linux.h
@@ -64,12 +64,12 @@
typedef struct work_struct _workitem;
-__inline static struct list_head *get_next(struct list_head *list)
+static inline struct list_head *get_next(struct list_head *list)
{
return list->next;
}
-__inline static struct list_head *get_list_head(struct __queue *queue)
+static inline struct list_head *get_list_head(struct __queue *queue)
{
return (&(queue->queue));
}
@@ -78,28 +78,28 @@ __inline static struct list_head *get_list_head(struct __queue *queue)
#define LIST_CONTAINOR(ptr, type, member) \
container_of(ptr, type, member)
-__inline static void _set_timer(_timer *ptimer, u32 delay_time)
+static inline void _set_timer(_timer *ptimer, u32 delay_time)
{
mod_timer(ptimer , (jiffies+(delay_time*HZ/1000)));
}
-__inline static void _cancel_timer(_timer *ptimer, u8 *bcancelled)
+static inline void _cancel_timer(_timer *ptimer, u8 *bcancelled)
{
del_timer_sync(ptimer);
*bcancelled = true;/* true == 1; false == 0 */
}
-__inline static void _init_workitem(_workitem *pwork, void *pfunc, void *cntx)
+static inline void _init_workitem(_workitem *pwork, void *pfunc, void *cntx)
{
INIT_WORK(pwork, pfunc);
}
-__inline static void _set_workitem(_workitem *pwork)
+static inline void _set_workitem(_workitem *pwork)
{
schedule_work(pwork);
}
-__inline static void _cancel_workitem_sync(_workitem *pwork)
+static inline void _cancel_workitem_sync(_workitem *pwork)
{
cancel_work_sync(pwork);
}
diff --git a/drivers/staging/rtl8723bs/include/rtw_debug.h b/drivers/staging/rtl8723bs/include/rtw_debug.h
index 216d9492575e..22fc5d730d7b 100644
--- a/drivers/staging/rtl8723bs/include/rtw_debug.h
+++ b/drivers/staging/rtl8723bs/include/rtw_debug.h
@@ -267,81 +267,4 @@ void mac_reg_dump(void *sel, struct adapter *adapter);
void bb_reg_dump(void *sel, struct adapter *adapter);
void rf_reg_dump(void *sel, struct adapter *adapter);
-#ifdef PROC_DEBUG
-ssize_t proc_set_write_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-int proc_get_read_reg(struct seq_file *m, void *v);
-ssize_t proc_set_read_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_fwstate(struct seq_file *m, void *v);
-int proc_get_sec_info(struct seq_file *m, void *v);
-int proc_get_mlmext_state(struct seq_file *m, void *v);
-
-int proc_get_roam_flags(struct seq_file *m, void *v);
-ssize_t proc_set_roam_flags(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-int proc_get_roam_param(struct seq_file *m, void *v);
-ssize_t proc_set_roam_param(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-ssize_t proc_set_roam_tgt_addr(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_qos_option(struct seq_file *m, void *v);
-int proc_get_ht_option(struct seq_file *m, void *v);
-int proc_get_rf_info(struct seq_file *m, void *v);
-int proc_get_survey_info(struct seq_file *m, void *v);
-int proc_get_ap_info(struct seq_file *m, void *v);
-int proc_get_adapter_state(struct seq_file *m, void *v);
-int proc_get_trx_info(struct seq_file *m, void *v);
-int proc_get_rate_ctl(struct seq_file *m, void *v);
-ssize_t proc_set_rate_ctl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-int proc_get_suspend_resume_info(struct seq_file *m, void *v);
-
-ssize_t proc_set_fwdl_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-ssize_t proc_set_wait_hiq_empty(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_all_sta_info(struct seq_file *m, void *v);
-
-int proc_get_rx_signal(struct seq_file *m, void *v);
-ssize_t proc_set_rx_signal(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-int proc_get_hw_status(struct seq_file *m, void *v);
-
-int proc_get_ht_enable(struct seq_file *m, void *v);
-ssize_t proc_set_ht_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_bw_mode(struct seq_file *m, void *v);
-ssize_t proc_set_bw_mode(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_ampdu_enable(struct seq_file *m, void *v);
-ssize_t proc_set_ampdu_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_rx_ampdu(struct seq_file *m, void *v);
-ssize_t proc_set_rx_ampdu(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_rx_stbc(struct seq_file *m, void *v);
-ssize_t proc_set_rx_stbc(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_en_fwps(struct seq_file *m, void *v);
-ssize_t proc_set_en_fwps(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-/* int proc_get_two_path_rssi(struct seq_file *m, void *v); */
-int proc_get_rssi_disp(struct seq_file *m, void *v);
-ssize_t proc_set_rssi_disp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_btcoex_dbg(struct seq_file *m, void *v);
-ssize_t proc_set_btcoex_dbg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-int proc_get_btcoex_info(struct seq_file *m, void *v);
-
-int proc_get_odm_dbg_comp(struct seq_file *m, void *v);
-ssize_t proc_set_odm_dbg_comp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-int proc_get_odm_dbg_level(struct seq_file *m, void *v);
-ssize_t proc_set_odm_dbg_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-int proc_get_odm_adaptivity(struct seq_file *m, void *v);
-ssize_t proc_set_odm_adaptivity(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-
-#ifdef CONFIG_DBG_COUNTER
-int proc_get_rx_logs(struct seq_file *m, void *v);
-int proc_get_tx_logs(struct seq_file *m, void *v);
-int proc_get_int_logs(struct seq_file *m, void *v);
-#endif
-
-#endif /* PROC_DEBUG */
-
#endif /* __RTW_DEBUG_H__ */
diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h
index d3c07d1c36e9..362737b83c3a 100644
--- a/drivers/staging/rtl8723bs/include/rtw_mlme.h
+++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h
@@ -81,15 +81,13 @@ enum dot11AuthAlgrthmNum {
};
/* Scan type including active and passive scan. */
-typedef enum _RT_SCAN_TYPE
-{
+typedef enum _RT_SCAN_TYPE {
SCAN_PASSIVE,
SCAN_ACTIVE,
SCAN_MIX,
}RT_SCAN_TYPE, *PRT_SCAN_TYPE;
-enum _BAND
-{
+enum _BAND {
GHZ24_50 = 0,
GHZ_50,
GHZ_24,
@@ -498,13 +496,13 @@ extern sint rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv);
extern sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, sint keyid, u8 set_tx, bool enqueue);
extern sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv);
-__inline static u8 *get_bssid(struct mlme_priv *pmlmepriv)
+static inline u8 *get_bssid(struct mlme_priv *pmlmepriv)
{ /* if sta_mode:pmlmepriv->cur_network.network.MacAddress => bssid */
/* if adhoc_mode:pmlmepriv->cur_network.network.MacAddress => ibss mac address */
return pmlmepriv->cur_network.network.MacAddress;
}
-__inline static sint check_fwstate(struct mlme_priv *pmlmepriv, sint state)
+static inline sint check_fwstate(struct mlme_priv *pmlmepriv, sint state)
{
if (pmlmepriv->fw_state & state)
return true;
@@ -512,7 +510,7 @@ __inline static sint check_fwstate(struct mlme_priv *pmlmepriv, sint state)
return false;
}
-__inline static sint get_fwstate(struct mlme_priv *pmlmepriv)
+static inline sint get_fwstate(struct mlme_priv *pmlmepriv)
{
return pmlmepriv->fw_state;
}
@@ -524,7 +522,7 @@ __inline static sint get_fwstate(struct mlme_priv *pmlmepriv)
* ### NOTE:#### (!!!!)
* MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
*/
-__inline static void set_fwstate(struct mlme_priv *pmlmepriv, sint state)
+static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state)
{
pmlmepriv->fw_state |= state;
/* FOR HW integration */
@@ -533,7 +531,7 @@ __inline static void set_fwstate(struct mlme_priv *pmlmepriv, sint state)
}
}
-__inline static void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state)
+static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state)
{
pmlmepriv->fw_state &= ~state;
/* FOR HW integration */
@@ -546,7 +544,7 @@ __inline static void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state)
* No Limit on the calling context,
* therefore set it to be the critical section...
*/
-__inline static void clr_fwstate(struct mlme_priv *pmlmepriv, sint state)
+static inline void clr_fwstate(struct mlme_priv *pmlmepriv, sint state)
{
spin_lock_bh(&pmlmepriv->lock);
if (check_fwstate(pmlmepriv, state) == true)
@@ -554,7 +552,7 @@ __inline static void clr_fwstate(struct mlme_priv *pmlmepriv, sint state)
spin_unlock_bh(&pmlmepriv->lock);
}
-__inline static void set_scanned_network_val(struct mlme_priv *pmlmepriv, sint val)
+static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, sint val)
{
spin_lock_bh(&pmlmepriv->lock);
pmlmepriv->num_of_scanned = val;
diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
index 733bb9425448..fd3cf955c9f8 100644
--- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
@@ -535,7 +535,7 @@ struct mlme_ext_priv
};
void init_mlme_default_rate_set(struct adapter *padapter);
-int init_mlme_ext_priv(struct adapter *padapter);
+void init_mlme_ext_priv(struct adapter *padapter);
int init_hw_mlme_ext(struct adapter *padapter);
void free_mlme_ext_priv (struct mlme_ext_priv *pmlmeext);
extern void init_mlme_ext_timer(struct adapter *padapter);
@@ -650,7 +650,6 @@ void report_del_sta_event(struct adapter *padapter, unsigned char* MacAddr, unsi
void report_add_sta_event(struct adapter *padapter, unsigned char* MacAddr, int cam_idx);
void report_wmm_edca_update(struct adapter *padapter);
-void beacon_timing_control(struct adapter *padapter);
u8 chk_bmc_sleepq_cmd(struct adapter *padapter);
extern u8 set_tx_beacon_cmd(struct adapter *padapter);
unsigned int setup_beacon_frame(struct adapter *padapter, unsigned char *beacon_frame);
diff --git a/drivers/staging/rtl8723bs/include/rtw_recv.h b/drivers/staging/rtl8723bs/include/rtw_recv.h
index 5de946e66302..012d8f54814f 100644
--- a/drivers/staging/rtl8723bs/include/rtw_recv.h
+++ b/drivers/staging/rtl8723bs/include/rtw_recv.h
@@ -405,7 +405,7 @@ struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue);
void rtw_reordering_ctrl_timeout_handler(struct timer_list *t);
-__inline static u8 *get_rxmem(union recv_frame *precvframe)
+static inline u8 *get_rxmem(union recv_frame *precvframe)
{
/* always return rx_head... */
if (precvframe == NULL)
@@ -414,7 +414,7 @@ __inline static u8 *get_rxmem(union recv_frame *precvframe)
return precvframe->u.hdr.rx_head;
}
-__inline static u8 *get_recvframe_data(union recv_frame *precvframe)
+static inline u8 *get_recvframe_data(union recv_frame *precvframe)
{
/* alwasy return rx_data */
@@ -425,7 +425,7 @@ __inline static u8 *get_recvframe_data(union recv_frame *precvframe)
}
-__inline static u8 *recvframe_pull(union recv_frame *precvframe, sint sz)
+static inline u8 *recvframe_pull(union recv_frame *precvframe, sint sz)
{
/* rx_data += sz; move rx_data sz bytes hereafter */
@@ -450,7 +450,7 @@ __inline static u8 *recvframe_pull(union recv_frame *precvframe, sint sz)
}
-__inline static u8 *recvframe_put(union recv_frame *precvframe, sint sz)
+static inline u8 *recvframe_put(union recv_frame *precvframe, sint sz)
{
/* rx_tai += sz; move rx_tail sz bytes hereafter */
@@ -479,7 +479,7 @@ __inline static u8 *recvframe_put(union recv_frame *precvframe, sint sz)
-__inline static u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz)
+static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz)
{
/* rmv data from rx_tail (by yitsen) */
@@ -503,7 +503,7 @@ __inline static u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz)
}
-__inline static union recv_frame *rxmem_to_recvframe(u8 *rxmem)
+static inline union recv_frame *rxmem_to_recvframe(u8 *rxmem)
{
/* due to the design of 2048 bytes alignment of recv_frame, we can reference the union recv_frame */
/* from any given member of recv_frame. */
@@ -513,13 +513,13 @@ __inline static union recv_frame *rxmem_to_recvframe(u8 *rxmem)
}
-__inline static sint get_recvframe_len(union recv_frame *precvframe)
+static inline sint get_recvframe_len(union recv_frame *precvframe)
{
return precvframe->u.hdr.len;
}
-__inline static s32 translate_percentage_to_dbm(u32 SignalStrengthIndex)
+static inline s32 translate_percentage_to_dbm(u32 SignalStrengthIndex)
{
s32 SignalPower; /* in dBm. */
diff --git a/drivers/staging/rtl8723bs/include/sta_info.h b/drivers/staging/rtl8723bs/include/sta_info.h
index b9df42d0677e..3acce5630f8e 100644
--- a/drivers/staging/rtl8723bs/include/sta_info.h
+++ b/drivers/staging/rtl8723bs/include/sta_info.h
@@ -348,7 +348,7 @@ struct sta_priv {
};
-__inline static u32 wifi_mac_hash(u8 *mac)
+static inline u32 wifi_mac_hash(u8 *mac)
{
u32 x;
diff --git a/drivers/staging/rtl8723bs/include/wifi.h b/drivers/staging/rtl8723bs/include/wifi.h
index 8c50bbb20f3b..2faf83704ff0 100644
--- a/drivers/staging/rtl8723bs/include/wifi.h
+++ b/drivers/staging/rtl8723bs/include/wifi.h
@@ -347,7 +347,7 @@ enum WIFI_REG_DOMAIN {
(addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \
)
-__inline static int IS_MCAST(unsigned char *da)
+static inline int IS_MCAST(unsigned char *da)
{
if ((*da) & 0x01)
return true;
@@ -355,20 +355,20 @@ __inline static int IS_MCAST(unsigned char *da)
return false;
}
-__inline static unsigned char * get_ra(unsigned char *pframe)
+static inline unsigned char * get_ra(unsigned char *pframe)
{
unsigned char *ra;
ra = GetAddr1Ptr(pframe);
return ra;
}
-__inline static unsigned char * get_ta(unsigned char *pframe)
+static inline unsigned char * get_ta(unsigned char *pframe)
{
unsigned char *ta;
ta = GetAddr2Ptr(pframe);
return ta;
}
-__inline static unsigned char * get_da(unsigned char *pframe)
+static inline unsigned char * get_da(unsigned char *pframe)
{
unsigned char *da;
unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
@@ -392,7 +392,7 @@ __inline static unsigned char * get_da(unsigned char *pframe)
}
-__inline static unsigned char * get_sa(unsigned char *pframe)
+static inline unsigned char * get_sa(unsigned char *pframe)
{
unsigned char *sa;
unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
@@ -415,7 +415,7 @@ __inline static unsigned char * get_sa(unsigned char *pframe)
return sa;
}
-__inline static unsigned char * get_hdr_bssid(unsigned char *pframe)
+static inline unsigned char * get_hdr_bssid(unsigned char *pframe)
{
unsigned char *sa = NULL;
unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
@@ -439,7 +439,7 @@ __inline static unsigned char * get_hdr_bssid(unsigned char *pframe)
}
-__inline static int IsFrameTypeCtrl(unsigned char *pframe)
+static inline int IsFrameTypeCtrl(unsigned char *pframe)
{
if (WIFI_CTRL_TYPE == GetFrameType(pframe))
return true;
diff --git a/drivers/staging/rtl8723bs/include/wlan_bssdef.h b/drivers/staging/rtl8723bs/include/wlan_bssdef.h
index 88890b1c3c4c..723fc5b546ef 100644
--- a/drivers/staging/rtl8723bs/include/wlan_bssdef.h
+++ b/drivers/staging/rtl8723bs/include/wlan_bssdef.h
@@ -223,7 +223,7 @@ struct wlan_bssid_ex {
u8 IEs[MAX_IE_SZ]; /* timestamp, beacon interval, and capability information) */
} __packed;
-__inline static uint get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss)
+static inline uint get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss)
{
return (sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + bss->IELength);
}
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
index 9bc685632651..f819abb756dc 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
@@ -19,8 +19,6 @@
#define RTW_MAX_REMAIN_ON_CHANNEL_DURATION 5000 /* ms */
#define RTW_MAX_NUM_PMKIDS 4
-#define RTW_CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
-
static const u32 rtw_cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
@@ -2024,8 +2022,6 @@ static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
- padapter->mlmepriv.not_indic_disco = true;
-
old_type = rtw_wdev->iftype;
rtw_set_to_roam(padapter, 0);
@@ -2047,8 +2043,6 @@ static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
}
leave_ibss:
- padapter->mlmepriv.not_indic_disco = false;
-
return 0;
}
@@ -2246,8 +2240,6 @@ static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev,
DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
- padapter->mlmepriv.not_indic_disco = true;
-
rtw_set_to_roam(padapter, 0);
rtw_scan_abort(padapter);
@@ -2261,8 +2253,6 @@ static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev,
rtw_free_assoc_resources(padapter, 1);
rtw_pwr_wakeup(padapter);
- padapter->mlmepriv.not_indic_disco = false;
-
DBG_871X(FUNC_NDEV_FMT" return 0\n", FUNC_NDEV_ARG(ndev));
return 0;
}
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
index 99e6b1028f71..d1b199e3e5bd 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
@@ -21,13 +21,10 @@
#define RATE_COUNT 4
/* combo scan */
-#define WEXT_CSCAN_AMOUNT 9
-#define WEXT_CSCAN_BUF_LEN 360
#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00"
#define WEXT_CSCAN_HEADER_SIZE 12
#define WEXT_CSCAN_SSID_SECTION 'S'
#define WEXT_CSCAN_CHANNEL_SECTION 'C'
-#define WEXT_CSCAN_NPROBE_SECTION 'N'
#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A'
#define WEXT_CSCAN_PASV_DWELL_SECTION 'P'
#define WEXT_CSCAN_HOME_DWELL_SECTION 'H'
@@ -215,8 +212,6 @@ static char *translate_scan(struct adapter *padapter,
} else if (ht_cap) {
if (mcs_rate&0x8000) { /* MCS15 */
max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130);
- } else if (mcs_rate&0x0080) { /* MCS7 */
- max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65);
} else { /* default MCS7 */
/* DBG_871X("wx_get_scan, mcs_rate_bitmap = 0x%x\n", mcs_rate); */
max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65);
@@ -4912,7 +4907,6 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_
s32 k;
const iw_handler *priv; /* Private ioctl */
const struct iw_priv_args *priv_args; /* Private ioctl description */
- u32 num_priv; /* Number of ioctl */
u32 num_priv_args; /* Number of descriptions */
iw_handler handler;
int temp;
@@ -4948,7 +4942,6 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_
priv = rtw_private_handler;
priv_args = rtw_private_args;
- num_priv = ARRAY_SIZE(rtw_private_handler);
num_priv_args = ARRAY_SIZE(rtw_private_args);
if (num_priv_args == 0) {
diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c
index 544e799d0a03..ec3a75485233 100644
--- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c
@@ -239,9 +239,6 @@ static void loadparam(struct adapter *padapter, _nic_hdl pnetdev)
registry_par->channel = (u8)rtw_channel;
registry_par->wireless_mode = (u8)rtw_wireless_mode;
- if (registry_par->channel > 14)
- registry_par->channel = 1;
-
registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense ;
registry_par->vcs_type = (u8)rtw_vcs_type;
registry_par->rts_thresh = (u16)rtw_rts_thresh;
@@ -448,12 +445,6 @@ static int rtw_ndev_notifier_call(struct notifier_block *nb, unsigned long state
DBG_871X_LEVEL(_drv_info_, FUNC_NDEV_FMT " state:%lu\n", FUNC_NDEV_ARG(dev), state);
- switch (state) {
- case NETDEV_CHANGENAME:
- rtw_adapter_proc_replace(dev);
- break;
- }
-
return NOTIFY_DONE;
}
@@ -478,7 +469,6 @@ static int rtw_ndev_init(struct net_device *dev)
DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(adapter));
strncpy(adapter->old_ifname, dev->name, IFNAMSIZ);
- rtw_adapter_proc_init(dev);
return 0;
}
@@ -488,7 +478,6 @@ static void rtw_ndev_uninit(struct net_device *dev)
struct adapter *adapter = rtw_netdev_priv(dev);
DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(adapter));
- rtw_adapter_proc_deinit(dev);
}
static const struct net_device_ops rtw_netdev_ops = {
@@ -768,11 +757,7 @@ u8 rtw_init_drv_sw(struct adapter *padapter)
goto exit;
}
- if (init_mlme_ext_priv(padapter) == _FAIL) {
- RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_ext_priv\n"));
- ret8 = _FAIL;
- goto exit;
- }
+ init_mlme_ext_priv(padapter);
if (_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) {
DBG_871X("Can't _rtw_init_xmit_priv\n");
@@ -1361,13 +1346,12 @@ void rtw_suspend_wow(struct adapter *padapter)
#endif /* ifdef CONFIG_WOWLAN */
#ifdef CONFIG_AP_WOWLAN
-int rtw_suspend_ap_wow(struct adapter *padapter)
+void rtw_suspend_ap_wow(struct adapter *padapter)
{
u8 ch, bw, offset;
struct net_device *pnetdev = padapter->pnetdev;
struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
struct wowlan_ioctl_param poidparam;
- int ret = _SUCCESS;
DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter));
@@ -1409,7 +1393,6 @@ int rtw_suspend_ap_wow(struct adapter *padapter)
rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, 0, "AP-WOWLAN");
DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter));
- return ret;
}
#endif /* ifdef CONFIG_AP_WOWLAN */
diff --git a/drivers/staging/rtl8723bs/os_dep/osdep_service.c b/drivers/staging/rtl8723bs/os_dep/osdep_service.c
index 62fdd24ba427..25a80041ce87 100644
--- a/drivers/staging/rtl8723bs/os_dep/osdep_service.c
+++ b/drivers/staging/rtl8723bs/os_dep/osdep_service.c
@@ -318,13 +318,9 @@ error:
void rtw_buf_free(u8 **buf, u32 *buf_len)
{
- u32 ori_len;
-
if (!buf || !buf_len)
return;
- ori_len = *buf_len;
-
if (*buf) {
*buf_len = 0;
kfree(*buf);
diff --git a/drivers/staging/rtl8723bs/os_dep/rtw_proc.c b/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
deleted file mode 100644
index 5f950fda48ea..000000000000
--- a/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
+++ /dev/null
@@ -1,779 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2013 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-#include <drv_types.h>
-#include <rtw_debug.h>
-#include "rtw_proc.h"
-
-#ifdef PROC_DEBUG
-
-static struct proc_dir_entry *rtw_proc;
-
-#define RTW_PROC_NAME "rtl8723bs"
-
-#define get_proc_net init_net.proc_net
-
-inline struct proc_dir_entry *rtw_proc_create_dir(const char *name, struct proc_dir_entry *parent, void *data)
-{
- struct proc_dir_entry *entry;
-
- entry = proc_mkdir_data(name, S_IRUGO|S_IXUGO, parent, data);
-
- return entry;
-}
-
-inline struct proc_dir_entry *rtw_proc_create_entry(const char *name, struct proc_dir_entry *parent,
- const struct file_operations *fops, void *data)
-{
- struct proc_dir_entry *entry;
-
- entry = proc_create_data(name, S_IFREG|S_IRUGO, parent, fops, data);
-
- return entry;
-}
-
-static int proc_get_dummy(struct seq_file *m, void *v)
-{
- return 0;
-}
-
-static int proc_get_drv_version(struct seq_file *m, void *v)
-{
- dump_drv_version(m);
- return 0;
-}
-
-static int proc_get_log_level(struct seq_file *m, void *v)
-{
- dump_log_level(m);
- return 0;
-}
-
-static ssize_t proc_set_log_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- char tmp[32];
- int log_level;
-
- if (count < 1)
- return -EINVAL;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- sscanf(tmp, "%d ", &log_level);
- if (log_level >= _drv_always_ && log_level <= _drv_debug_) {
- GlobalDebugLevel = log_level;
- printk("%d\n", GlobalDebugLevel);
- }
- } else {
- return -EFAULT;
- }
-
- return count;
-}
-
-/*
-* rtw_drv_proc:
-* init/deinit when register/unregister driver
-*/
-static const struct rtw_proc_hdl drv_proc_hdls[] = {
- {"ver_info", proc_get_drv_version, NULL},
- {"log_level", proc_get_log_level, proc_set_log_level},
-};
-
-static const int drv_proc_hdls_num = sizeof(drv_proc_hdls) / sizeof(struct rtw_proc_hdl);
-
-static int rtw_drv_proc_open(struct inode *inode, struct file *file)
-{
- /* struct net_device *dev = proc_get_parent_data(inode); */
- ssize_t index = (ssize_t)PDE_DATA(inode);
- const struct rtw_proc_hdl *hdl = drv_proc_hdls+index;
-
- return single_open(file, hdl->show, NULL);
-}
-
-static ssize_t rtw_drv_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
-{
- ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
- const struct rtw_proc_hdl *hdl = drv_proc_hdls+index;
- ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
-
- if (write)
- return write(file, buffer, count, pos, NULL);
-
- return -EROFS;
-}
-
-static const struct file_operations rtw_drv_proc_fops = {
- .owner = THIS_MODULE,
- .open = rtw_drv_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = rtw_drv_proc_write,
-};
-
-int rtw_drv_proc_init(void)
-{
- int ret = _FAIL;
- ssize_t i;
- struct proc_dir_entry *entry = NULL;
-
- if (rtw_proc) {
- rtw_warn_on(1);
- goto exit;
- }
-
- rtw_proc = rtw_proc_create_dir(RTW_PROC_NAME, get_proc_net, NULL);
-
- if (!rtw_proc) {
- rtw_warn_on(1);
- goto exit;
- }
-
- for (i = 0; i < drv_proc_hdls_num; i++) {
- entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_fops, (void *)i);
- if (!entry) {
- rtw_warn_on(1);
- goto exit;
- }
- }
-
- ret = _SUCCESS;
-
-exit:
- return ret;
-}
-
-void rtw_drv_proc_deinit(void)
-{
- int i;
-
- if (!rtw_proc)
- return;
-
- for (i = 0; i < drv_proc_hdls_num; i++)
- remove_proc_entry(drv_proc_hdls[i].name, rtw_proc);
-
- remove_proc_entry(RTW_PROC_NAME, get_proc_net);
- rtw_proc = NULL;
-}
-
-static int proc_get_sd_f0_reg_dump(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- sd_f0_reg_dump(m, adapter);
-
- return 0;
-}
-
-static int proc_get_mac_reg_dump(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- mac_reg_dump(m, adapter);
-
- return 0;
-}
-
-static int proc_get_bb_reg_dump(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- bb_reg_dump(m, adapter);
-
- return 0;
-}
-
-static int proc_get_rf_reg_dump(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- rf_reg_dump(m, adapter);
-
- return 0;
-}
-static int proc_get_linked_info_dump(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- if (padapter)
- DBG_871X_SEL_NL(m, "linked_info_dump :%s\n", (padapter->bLinkInfoDump)?"enable":"disable");
-
- return 0;
-}
-
-static ssize_t proc_set_linked_info_dump(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- char tmp[2];
- int mode = 0;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- if (padapter) {
- /* padapter->bLinkInfoDump = mode; */
- /* DBG_871X("linked_info_dump =%s\n", (padapter->bLinkInfoDump)?"enable":"disable"); */
- linked_info_dump(padapter, mode);
- }
-
- }
-
- return count;
-
-}
-
-static int proc_get_rx_info(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct dvobj_priv *psdpriv = padapter->dvobj;
- struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
-
- /* Counts of packets whose seq_num is less than preorder_ctrl->indicate_seq, Ex delay, retransmission, redundant packets and so on */
- DBG_871X_SEL_NL(m,"Counts of Packets Whose Seq_Num Less Than Reorder Control Seq_Num: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_drop_count);
- /* How many times the Rx Reorder Timer is triggered. */
- DBG_871X_SEL_NL(m,"Rx Reorder Time-out Trigger Counts: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_forced_indicate_count);
- /* Total counts of packets loss */
- DBG_871X_SEL_NL(m,"Rx Packet Loss Counts: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_loss_count);
- DBG_871X_SEL_NL(m,"Duplicate Management Frame Drop Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_dup_mgt_frame_drop_count);
- DBG_871X_SEL_NL(m,"AMPDU BA window shift Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_window_shift_cnt);
- return 0;
-}
-
-
-static ssize_t proc_reset_rx_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct dvobj_priv *psdpriv = padapter->dvobj;
- struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
- char cmd[32];
- if (buffer && !copy_from_user(cmd, buffer, sizeof(cmd))) {
- if ('0' == cmd[0]) {
- pdbgpriv->dbg_rx_ampdu_drop_count = 0;
- pdbgpriv->dbg_rx_ampdu_forced_indicate_count = 0;
- pdbgpriv->dbg_rx_ampdu_loss_count = 0;
- pdbgpriv->dbg_rx_dup_mgt_frame_drop_count = 0;
- pdbgpriv->dbg_rx_ampdu_window_shift_cnt = 0;
- }
- }
-
- return count;
-}
-
-static int proc_get_cam(struct seq_file *m, void *v)
-{
- return 0;
-}
-
-static ssize_t proc_set_cam(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *adapter;
-
- char tmp[32];
- char cmd[5];
- u8 id;
-
- adapter = (struct adapter *)rtw_netdev_priv(dev);
- if (!adapter)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- /* c <id>: clear specific cam entry */
- /* wfc <id>: write specific cam entry from cam cache */
-
- int num = sscanf(tmp, "%4s %hhu", cmd, &id);
-
- if (num < 2)
- return count;
- if (id >= TOTAL_CAM_ENTRY)
- return -EINVAL;
-
- if (strcmp("c", cmd) == 0) {
- _clear_cam_entry(adapter, id);
- adapter->securitypriv.hw_decrypted = false; /* temporarily set this for TX path to use SW enc */
- } else if (strcmp("wfc", cmd) == 0) {
- write_cam_from_cache(adapter, id);
- }
- }
-
- return count;
-}
-
-static int proc_get_cam_cache(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
- struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
- u8 i;
-
- DBG_871X_SEL_NL(m, "cam bitmap:0x%016llx\n", dvobj->cam_ctl.bitmap);
-
- DBG_871X_SEL_NL(m, "%-2s %-6s %-17s %-32s %-3s %-7s"
- /* %-2s %-2s %-4s %-5s" */
- "\n"
- , "id", "ctrl", "addr", "key", "kid", "type"
- /* "MK", "GK", "MFB", "valid" */
- );
-
- for (i = 0; i < 32; i++) {
- if (dvobj->cam_cache[i].ctrl != 0)
- DBG_871X_SEL_NL(m, "%2u 0x%04x "MAC_FMT" "KEY_FMT" %3u %-7s"
- /* %2u %2u 0x%02x %5u" */
- "\n", i
- , dvobj->cam_cache[i].ctrl
- , MAC_ARG(dvobj->cam_cache[i].mac)
- , KEY_ARG(dvobj->cam_cache[i].key)
- , (dvobj->cam_cache[i].ctrl)&0x03
- , security_type_str(((dvobj->cam_cache[i].ctrl)>>2)&0x07)
- /* ((dvobj->cam_cache[i].ctrl)>>5)&0x01 */
- /* ((dvobj->cam_cache[i].ctrl)>>6)&0x01 */
- /* ((dvobj->cam_cache[i].ctrl)>>8)&0x7f */
- /* ((dvobj->cam_cache[i].ctrl)>>15)&0x01 */
- );
- }
-
- return 0;
-}
-
-/*
-* rtw_adapter_proc:
-* init/deinit when register/unregister net_device
-*/
-static const struct rtw_proc_hdl adapter_proc_hdls[] = {
- {"write_reg", proc_get_dummy, proc_set_write_reg},
- {"read_reg", proc_get_read_reg, proc_set_read_reg},
- {"fwstate", proc_get_fwstate, NULL},
- {"sec_info", proc_get_sec_info, NULL},
- {"mlmext_state", proc_get_mlmext_state, NULL},
- {"qos_option", proc_get_qos_option, NULL},
- {"ht_option", proc_get_ht_option, NULL},
- {"rf_info", proc_get_rf_info, NULL},
- {"survey_info", proc_get_survey_info, NULL},
- {"ap_info", proc_get_ap_info, NULL},
- {"adapter_state", proc_get_adapter_state, NULL},
- {"trx_info", proc_get_trx_info, NULL},
- {"rate_ctl", proc_get_rate_ctl, proc_set_rate_ctl},
- {"cam", proc_get_cam, proc_set_cam},
- {"cam_cache", proc_get_cam_cache, NULL},
- {"suspend_info", proc_get_suspend_resume_info, NULL},
- {"rx_info", proc_get_rx_info, proc_reset_rx_info},
-
- {"roam_flags", proc_get_roam_flags, proc_set_roam_flags},
- {"roam_param", proc_get_roam_param, proc_set_roam_param},
- {"roam_tgt_addr", proc_get_dummy, proc_set_roam_tgt_addr},
-
- {"sd_f0_reg_dump", proc_get_sd_f0_reg_dump, NULL},
-
- {"fwdl_test_case", proc_get_dummy, proc_set_fwdl_test_case},
- {"wait_hiq_empty", proc_get_dummy, proc_set_wait_hiq_empty},
-
- {"mac_reg_dump", proc_get_mac_reg_dump, NULL},
- {"bb_reg_dump", proc_get_bb_reg_dump, NULL},
- {"rf_reg_dump", proc_get_rf_reg_dump, NULL},
-
- {"all_sta_info", proc_get_all_sta_info, NULL},
-
- {"rx_signal", proc_get_rx_signal, proc_set_rx_signal},
- {"hw_info", proc_get_hw_status, NULL},
-
- {"ht_enable", proc_get_ht_enable, proc_set_ht_enable},
- {"bw_mode", proc_get_bw_mode, proc_set_bw_mode},
- {"ampdu_enable", proc_get_ampdu_enable, proc_set_ampdu_enable},
- {"rx_stbc", proc_get_rx_stbc, proc_set_rx_stbc},
- {"rx_ampdu", proc_get_rx_ampdu, proc_set_rx_ampdu},
-
- {"en_fwps", proc_get_en_fwps, proc_set_en_fwps},
-
- /* path_rssi", proc_get_two_path_rssi, NULL}, */
- {"rssi_disp", proc_get_rssi_disp, proc_set_rssi_disp},
-
- {"btcoex_dbg", proc_get_btcoex_dbg, proc_set_btcoex_dbg},
- {"btcoex", proc_get_btcoex_info, NULL},
-
- {"linked_info_dump", proc_get_linked_info_dump, proc_set_linked_info_dump},
-#ifdef CONFIG_DBG_COUNTER
- {"rx_logs", proc_get_rx_logs, NULL},
- {"tx_logs", proc_get_tx_logs, NULL},
- {"int_logs", proc_get_int_logs, NULL},
-#endif
-};
-
-static const int adapter_proc_hdls_num = sizeof(adapter_proc_hdls) / sizeof(struct rtw_proc_hdl);
-
-static int rtw_adapter_proc_open(struct inode *inode, struct file *file)
-{
- ssize_t index = (ssize_t)PDE_DATA(inode);
- const struct rtw_proc_hdl *hdl = adapter_proc_hdls+index;
-
- return single_open(file, hdl->show, proc_get_parent_data(inode));
-}
-
-static ssize_t rtw_adapter_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
-{
- ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
- const struct rtw_proc_hdl *hdl = adapter_proc_hdls+index;
- ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
-
- if (write)
- return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private);
-
- return -EROFS;
-}
-
-static const struct file_operations rtw_adapter_proc_fops = {
- .owner = THIS_MODULE,
- .open = rtw_adapter_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = rtw_adapter_proc_write,
-};
-
-int proc_get_odm_dbg_comp(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- rtw_odm_dbg_comp_msg(m, adapter);
-
- return 0;
-}
-
-ssize_t proc_set_odm_dbg_comp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
- char tmp[32];
-
- u64 dbg_comp;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%llx", &dbg_comp);
-
- if (num != 1)
- return count;
-
- rtw_odm_dbg_comp_set(adapter, dbg_comp);
- }
-
- return count;
-}
-
-int proc_get_odm_dbg_level(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- rtw_odm_dbg_level_msg(m, adapter);
-
- return 0;
-}
-
-ssize_t proc_set_odm_dbg_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
- char tmp[32];
-
- u32 dbg_level;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%u", &dbg_level);
-
- if (num != 1)
- return count;
-
- rtw_odm_dbg_level_set(adapter, dbg_level);
- }
-
- return count;
-}
-
-static int proc_get_odm_ability(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
-
- rtw_odm_ability_msg(m, adapter);
-
- return 0;
-}
-
-static ssize_t proc_set_odm_ability(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
- char tmp[32];
-
- u32 ability;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%x", &ability);
-
- if (num != 1)
- return count;
-
- rtw_odm_ability_set(adapter, ability);
- }
-
- return count;
-}
-
-int proc_get_odm_adaptivity(struct seq_file *m, void *v)
-{
- struct net_device *dev = m->private;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-
- rtw_odm_adaptivity_parm_msg(m, padapter);
-
- return 0;
-}
-
-ssize_t proc_set_odm_adaptivity(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- char tmp[32];
- u32 TH_L2H_ini;
- s8 TH_EDCCA_HL_diff;
- u32 IGI_Base;
- int ForceEDCCA;
- u8 AdapEn_RSSI;
- u8 IGI_LowerBound;
-
- if (count < 1)
- return -EFAULT;
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-
- int num = sscanf(tmp, "%x %hhd %x %d %hhu %hhu",
- &TH_L2H_ini, &TH_EDCCA_HL_diff, &IGI_Base, &ForceEDCCA, &AdapEn_RSSI, &IGI_LowerBound);
-
- if (num != 6)
- return count;
-
- rtw_odm_adaptivity_parm_set(padapter, (s8)TH_L2H_ini, TH_EDCCA_HL_diff, (s8)IGI_Base, (bool)ForceEDCCA, AdapEn_RSSI, IGI_LowerBound);
- }
-
- return count;
-}
-
-/*
-* rtw_odm_proc:
-* init/deinit when register/unregister net_device, along with rtw_adapter_proc
-*/
-static const struct rtw_proc_hdl odm_proc_hdls[] = {
- {"dbg_comp", proc_get_odm_dbg_comp, proc_set_odm_dbg_comp},
- {"dbg_level", proc_get_odm_dbg_level, proc_set_odm_dbg_level},
- {"ability", proc_get_odm_ability, proc_set_odm_ability},
- {"adaptivity", proc_get_odm_adaptivity, proc_set_odm_adaptivity},
-};
-
-static const int odm_proc_hdls_num = sizeof(odm_proc_hdls) / sizeof(struct rtw_proc_hdl);
-
-static int rtw_odm_proc_open(struct inode *inode, struct file *file)
-{
- ssize_t index = (ssize_t)PDE_DATA(inode);
- const struct rtw_proc_hdl *hdl = odm_proc_hdls+index;
-
- return single_open(file, hdl->show, proc_get_parent_data(inode));
-}
-
-static ssize_t rtw_odm_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
-{
- ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
- const struct rtw_proc_hdl *hdl = odm_proc_hdls+index;
- ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
-
- if (write)
- return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private);
-
- return -EROFS;
-}
-
-static const struct file_operations rtw_odm_proc_fops = {
- .owner = THIS_MODULE,
- .open = rtw_odm_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = rtw_odm_proc_write,
-};
-
-static struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev)
-{
- struct proc_dir_entry *dir_odm = NULL;
- struct proc_dir_entry *entry = NULL;
- struct adapter *adapter = rtw_netdev_priv(dev);
- ssize_t i;
-
- if (!adapter->dir_dev) {
- rtw_warn_on(1);
- goto exit;
- }
-
- if (adapter->dir_odm) {
- rtw_warn_on(1);
- goto exit;
- }
-
- dir_odm = rtw_proc_create_dir("odm", adapter->dir_dev, dev);
- if (!dir_odm) {
- rtw_warn_on(1);
- goto exit;
- }
-
- adapter->dir_odm = dir_odm;
-
- for (i = 0; i < odm_proc_hdls_num; i++) {
- entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_fops, (void *)i);
- if (!entry) {
- rtw_warn_on(1);
- goto exit;
- }
- }
-
-exit:
- return dir_odm;
-}
-
-static void rtw_odm_proc_deinit(struct adapter *adapter)
-{
- struct proc_dir_entry *dir_odm = NULL;
- int i;
-
- dir_odm = adapter->dir_odm;
-
- if (!dir_odm) {
- rtw_warn_on(1);
- return;
- }
-
- for (i = 0; i < odm_proc_hdls_num; i++)
- remove_proc_entry(odm_proc_hdls[i].name, dir_odm);
-
- remove_proc_entry("odm", adapter->dir_dev);
-
- adapter->dir_odm = NULL;
-}
-
-struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev)
-{
- struct proc_dir_entry *drv_proc = rtw_proc;
- struct proc_dir_entry *dir_dev = NULL;
- struct proc_dir_entry *entry = NULL;
- struct adapter *adapter = rtw_netdev_priv(dev);
- ssize_t i;
-
- if (!drv_proc) {
- rtw_warn_on(1);
- goto exit;
- }
-
- if (adapter->dir_dev) {
- rtw_warn_on(1);
- goto exit;
- }
-
- dir_dev = rtw_proc_create_dir(dev->name, drv_proc, dev);
- if (!dir_dev) {
- rtw_warn_on(1);
- goto exit;
- }
-
- adapter->dir_dev = dir_dev;
-
- for (i = 0; i < adapter_proc_hdls_num; i++) {
- entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_fops, (void *)i);
- if (!entry) {
- rtw_warn_on(1);
- goto exit;
- }
- }
-
- rtw_odm_proc_init(dev);
-
-exit:
- return dir_dev;
-}
-
-void rtw_adapter_proc_deinit(struct net_device *dev)
-{
- struct proc_dir_entry *drv_proc = rtw_proc;
- struct proc_dir_entry *dir_dev = NULL;
- struct adapter *adapter = rtw_netdev_priv(dev);
- int i;
-
- dir_dev = adapter->dir_dev;
-
- if (!dir_dev) {
- rtw_warn_on(1);
- return;
- }
-
- for (i = 0; i < adapter_proc_hdls_num; i++)
- remove_proc_entry(adapter_proc_hdls[i].name, dir_dev);
-
- rtw_odm_proc_deinit(adapter);
-
- remove_proc_entry(dev->name, drv_proc);
-
- adapter->dir_dev = NULL;
-}
-
-void rtw_adapter_proc_replace(struct net_device *dev)
-{
- struct proc_dir_entry *drv_proc = rtw_proc;
- struct proc_dir_entry *dir_dev = NULL;
- struct adapter *adapter = rtw_netdev_priv(dev);
- int i;
-
- dir_dev = adapter->dir_dev;
-
- if (!dir_dev) {
- rtw_warn_on(1);
- return;
- }
-
- for (i = 0; i < adapter_proc_hdls_num; i++)
- remove_proc_entry(adapter_proc_hdls[i].name, dir_dev);
-
- rtw_odm_proc_deinit(adapter);
-
- remove_proc_entry(adapter->old_ifname, drv_proc);
-
- adapter->dir_dev = NULL;
-
- rtw_adapter_proc_init(dev);
-
-}
-
-#endif /* PROC_DEBUG */
diff --git a/drivers/staging/rtl8723bs/os_dep/rtw_proc.h b/drivers/staging/rtl8723bs/os_dep/rtw_proc.h
deleted file mode 100644
index c7e6f62b61ef..000000000000
--- a/drivers/staging/rtl8723bs/os_dep/rtw_proc.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2013 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-#ifndef __RTW_PROC_H__
-#define __RTW_PROC_H__
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
-struct rtw_proc_hdl {
- char *name;
- int (*show)(struct seq_file *, void *);
- ssize_t (*write)(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
-};
-
-#ifdef PROC_DEBUG
-
-int rtw_drv_proc_init(void);
-void rtw_drv_proc_deinit(void);
-struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev);
-void rtw_adapter_proc_deinit(struct net_device *dev);
-void rtw_adapter_proc_replace(struct net_device *dev);
-
-#else //!PROC_DEBUG
-
-static inline int rtw_drv_proc_init(void) {return 0;}
-static inline void rtw_drv_proc_deinit(void) {}
-static inline struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev){return NULL;}
-static inline void rtw_adapter_proc_deinit(struct net_device *dev){}
-static inline void rtw_adapter_proc_replace(struct net_device *dev){}
-
-#endif //!PROC_DEBUG
-
-#endif //__RTW_PROC_H__
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
index 540a7eed621d..d3784c44f6d0 100644
--- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
@@ -371,7 +371,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
rtw_hal_chip_configure(padapter);
- hal_btcoex_Initialize(padapter);
+ hal_btcoex_Initialize((void *) padapter);
/* 3 6. read efuse/eeprom data */
rtw_hal_read_chip_info(padapter);
@@ -620,12 +620,10 @@ static int __init rtw_drv_entry(void)
#endif /* BTCOEXVERSION */
sdio_drvpriv.drv_registered = true;
- rtw_drv_proc_init();
ret = sdio_register_driver(&sdio_drvpriv.r871xs_drv);
if (ret != 0) {
sdio_drvpriv.drv_registered = false;
- rtw_drv_proc_deinit();
rtw_ndev_notifier_unregister();
DBG_871X("%s: register driver failed!!(%d)\n", __func__, ret);
goto exit;
@@ -646,7 +644,6 @@ static void __exit rtw_drv_halt(void)
sdio_unregister_driver(&sdio_drvpriv.r871xs_drv);
- rtw_drv_proc_deinit();
rtw_ndev_notifier_unregister();
DBG_871X_LEVEL(_drv_always_, "module exit success\n");
diff --git a/drivers/staging/rtl8723bs/os_dep/wifi_regd.c b/drivers/staging/rtl8723bs/os_dep/wifi_regd.c
index aa2f62acc994..578b9f734231 100644
--- a/drivers/staging/rtl8723bs/os_dep/wifi_regd.c
+++ b/drivers/staging/rtl8723bs/os_dep/wifi_regd.c
@@ -33,11 +33,6 @@
REG_RULE(2467 - 10, 2472 + 10, 40, 0, 20, \
NL80211_RRF_PASSIVE_SCAN)
-/* 2G chan 14, PASSIVS SCAN, NO OFDM (B only) */
-#define RTW_2GHZ_CH14 \
- REG_RULE(2484 - 10, 2484 + 10, 40, 0, 20, \
- NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
-
static const struct ieee80211_regdomain rtw_regdom_rd = {
.n_reg_rules = 3,
.alpha2 = "99",
diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c
index 1128eec3bd08..e853fa9cc950 100644
--- a/drivers/staging/rts5208/ms.c
+++ b/drivers/staging/rts5208/ms.c
@@ -3842,7 +3842,7 @@ int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip)
int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
- int retval = STATUS_FAIL;
+ int retval;
int bufflen;
unsigned int lun = SCSI_LUN(srb);
u8 *buf = NULL;
diff --git a/drivers/staging/rts5208/rtsx_transport.c b/drivers/staging/rts5208/rtsx_transport.c
index 8277d7895608..561851cc8780 100644
--- a/drivers/staging/rts5208/rtsx_transport.c
+++ b/drivers/staging/rts5208/rtsx_transport.c
@@ -393,10 +393,9 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card,
*offset = 0;
*index = *index + 1;
}
- if ((i == (sg_cnt - 1)) || !resid)
- option = RTSX_SG_VALID | RTSX_SG_END | RTSX_SG_TRANS_DATA;
- else
- option = RTSX_SG_VALID | RTSX_SG_TRANS_DATA;
+ option = RTSX_SG_VALID | RTSX_SG_TRANS_DATA;
+ if ((i == sg_cnt - 1) || !resid)
+ option |= RTSX_SG_END;
rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
@@ -541,10 +540,9 @@ static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card,
dev_dbg(rtsx_dev(chip), "DMA addr: 0x%x, Len: 0x%x\n",
(unsigned int)addr, len);
+ option = RTSX_SG_VALID | RTSX_SG_TRANS_DATA;
if (j == (sg_cnt - 1))
- option = RTSX_SG_VALID | RTSX_SG_END | RTSX_SG_TRANS_DATA;
- else
- option = RTSX_SG_VALID | RTSX_SG_TRANS_DATA;
+ option |= RTSX_SG_END;
rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c
index a06045344301..25c31496757e 100644
--- a/drivers/staging/rts5208/sd.c
+++ b/drivers/staging/rts5208/sd.c
@@ -2573,17 +2573,13 @@ SD_UNLOCK_ENTRY:
retval = sd_sdr_tuning(chip);
if (retval != STATUS_SUCCESS) {
- if (sd20_mode) {
+ retval = sd_init_power(chip);
+ if (retval != STATUS_SUCCESS)
goto status_fail;
- } else {
- retval = sd_init_power(chip);
- if (retval != STATUS_SUCCESS)
- goto status_fail;
- try_sdio = false;
- sd20_mode = true;
- goto switch_fail;
- }
+ try_sdio = false;
+ sd20_mode = true;
+ goto switch_fail;
}
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
@@ -2598,17 +2594,13 @@ SD_UNLOCK_ENTRY:
if (read_lba0) {
retval = sd_read_lba0(chip);
if (retval != STATUS_SUCCESS) {
- if (sd20_mode) {
+ retval = sd_init_power(chip);
+ if (retval != STATUS_SUCCESS)
goto status_fail;
- } else {
- retval = sd_init_power(chip);
- if (retval != STATUS_SUCCESS)
- goto status_fail;
- try_sdio = false;
- sd20_mode = true;
- goto switch_fail;
- }
+ try_sdio = false;
+ sd20_mode = true;
+ goto switch_fail;
}
}
}
diff --git a/drivers/staging/sm750fb/ddk750.h b/drivers/staging/sm750fb/ddk750.h
index 482c1c6ba422..64ef4d258a91 100644
--- a/drivers/staging/sm750fb/ddk750.h
+++ b/drivers/staging/sm750fb/ddk750.h
@@ -2,9 +2,6 @@
/*
* Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
*
- * All rights are reserved. Reproduction or in part is prohibited
- * without the written consent of the copyright owner.
- *
* RegSC.h --- SM718 SDK
* This file contains the definitions for the System Configuration registers.
*/
diff --git a/drivers/staging/sm750fb/ddk750_swi2c.c b/drivers/staging/sm750fb/ddk750_swi2c.c
index 5c0ac747ea2b..0ef8d4ff2ef9 100644
--- a/drivers/staging/sm750fb/ddk750_swi2c.c
+++ b/drivers/staging/sm750fb/ddk750_swi2c.c
@@ -2,9 +2,6 @@
/*
* Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
*
- * All rights are reserved. Reproduction or in part is prohibited
- * without the written consent of the copyright owner.
- *
* swi2c.c --- SM750/SM718 DDK
* This file contains the source code for I2C using software
* implementation.
diff --git a/drivers/staging/sm750fb/ddk750_swi2c.h b/drivers/staging/sm750fb/ddk750_swi2c.h
index 5868feea791b..dfa166060da7 100644
--- a/drivers/staging/sm750fb/ddk750_swi2c.h
+++ b/drivers/staging/sm750fb/ddk750_swi2c.h
@@ -2,9 +2,6 @@
/*
* Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
*
- * All rights are reserved. Reproduction or in part is prohibited
- * without the written consent of the copyright owner.
- *
* swi2c.h --- SM750/SM718 DDK
* This file contains the definitions for i2c using software
* implementation.
diff --git a/drivers/staging/uwb/Kconfig b/drivers/staging/uwb/Kconfig
new file mode 100644
index 000000000000..259e053e1e09
--- /dev/null
+++ b/drivers/staging/uwb/Kconfig
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# UWB device configuration
+#
+
+menuconfig UWB
+ tristate "Ultra Wideband devices"
+ default n
+ select GENERIC_NET_UTILS
+ help
+ UWB is a high-bandwidth, low-power, point-to-point radio
+ technology using a wide spectrum (3.1-10.6GHz). It is
+ optimized for in-room use (480Mbps at 2 meters, 110Mbps at
+ 10m). It serves as the transport layer for other protocols,
+ such as Wireless USB (WUSB).
+
+ The topology is peer to peer; however, higher level
+ protocols (such as WUSB) might impose a master/slave
+ relationship.
+
+ Say Y here if your computer has UWB radio controllers (USB or PCI)
+ based. You will need to enable the radio controllers
+ below. It is ok to select all of them, no harm done.
+
+ For more help check the UWB and WUSB related files in
+ <file:Documentation/usb/>.
+
+ To compile the UWB stack as a module, choose M here.
+
+if UWB
+
+config UWB_HWA
+ tristate "UWB Radio Control driver for WUSB-compliant USB dongles (HWA)"
+ depends on USB
+ help
+ This driver enables the radio controller for HWA USB
+ devices. HWA stands for Host Wire Adapter, and it is a UWB
+ Radio Controller connected to your system via USB. Most of
+ them come with a Wireless USB host controller also.
+
+ To compile this driver select Y (built in) or M (module). It
+ is safe to select any even if you do not have the hardware.
+
+config UWB_WHCI
+ tristate "UWB Radio Control driver for WHCI-compliant cards"
+ depends on PCI
+ help
+ This driver enables the radio controller for WHCI cards.
+
+ WHCI is a specification developed by Intel
+ (http://www.intel.com/technology/comms/wusb/whci.htm) much
+ in the spirit of USB's EHCI, but for UWB and Wireless USB
+ radio/host controllers connected via memory mapping (eg:
+ PCI). Most of these cards come also with a Wireless USB host
+ controller.
+
+ To compile this driver select Y (built in) or M (module). It
+ is safe to select any even if you do not have the hardware.
+
+config UWB_I1480U
+ tristate "Support for Intel Wireless UWB Link 1480 HWA"
+ depends on UWB_HWA
+ select FW_LOADER
+ help
+ This driver enables support for the i1480 when connected via
+ USB. It consists of a firmware uploader that will enable it
+ to behave as an HWA device.
+
+ To compile this driver select Y (built in) or M (module). It
+ is safe to select any even if you do not have the hardware.
+
+endif # UWB
diff --git a/drivers/staging/uwb/Makefile b/drivers/staging/uwb/Makefile
new file mode 100644
index 000000000000..32f4de7afbd6
--- /dev/null
+++ b/drivers/staging/uwb/Makefile
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_UWB) += uwb.o
+obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o
+obj-$(CONFIG_UWB_HWA) += hwa-rc.o
+obj-$(CONFIG_UWB_I1480U) += i1480/
+
+uwb-objs := \
+ address.o \
+ allocator.o \
+ beacon.o \
+ driver.o \
+ drp.o \
+ drp-avail.o \
+ drp-ie.o \
+ est.o \
+ ie.o \
+ ie-rcv.o \
+ lc-dev.o \
+ lc-rc.o \
+ neh.o \
+ pal.o \
+ radio.o \
+ reset.o \
+ rsv.o \
+ scan.o \
+ uwb-debug.o \
+ uwbd.o
+
+umc-objs := \
+ umc-bus.o \
+ umc-dev.o \
+ umc-drv.o
diff --git a/drivers/staging/uwb/TODO b/drivers/staging/uwb/TODO
new file mode 100644
index 000000000000..abae57000534
--- /dev/null
+++ b/drivers/staging/uwb/TODO
@@ -0,0 +1,8 @@
+TODO: Remove in late 2019 unless there are users
+
+There seems to not be any real wireless USB devices anywhere in the wild
+anymore. It turned out to be a failed technology :(
+
+This will be removed from the tree if no one objects.
+
+Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/staging/uwb/address.c b/drivers/staging/uwb/address.c
new file mode 100644
index 000000000000..857d5cd56a95
--- /dev/null
+++ b/drivers/staging/uwb/address.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Address management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/random.h>
+#include <linux/etherdevice.h>
+
+#include "uwb-internal.h"
+
+
+/** Device Address Management command */
+struct uwb_rc_cmd_dev_addr_mgmt {
+ struct uwb_rccb rccb;
+ u8 bmOperationType;
+ u8 baAddr[6];
+} __attribute__((packed));
+
+
+/**
+ * Low level command for setting/getting UWB radio's addresses
+ *
+ * @hwarc: HWA Radio Control interface instance
+ * @bmOperationType:
+ * Set/get, MAC/DEV (see WUSB1.0[8.6.2.2])
+ * @baAddr: address buffer--assumed to have enough data to hold
+ * the address type requested.
+ * @reply: Pointer to reply buffer (can be stack allocated)
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * @cmd has to be allocated because USB cannot grok USB or vmalloc
+ * buffers depending on your combination of host architecture.
+ */
+static
+int uwb_rc_dev_addr_mgmt(struct uwb_rc *rc,
+ u8 bmOperationType, const u8 *baAddr,
+ struct uwb_rc_evt_dev_addr_mgmt *reply)
+{
+ int result;
+ struct uwb_rc_cmd_dev_addr_mgmt *cmd;
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_kzalloc;
+ cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_DEV_ADDR_MGMT);
+ cmd->bmOperationType = bmOperationType;
+ if (baAddr) {
+ size_t size = 0;
+ switch (bmOperationType >> 1) {
+ case 0: size = 2; break;
+ case 1: size = 6; break;
+ default: BUG();
+ }
+ memcpy(cmd->baAddr, baAddr, size);
+ }
+ reply->rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply->rceb.wEvent = UWB_RC_CMD_DEV_ADDR_MGMT;
+ result = uwb_rc_cmd(rc, "DEV-ADDR-MGMT",
+ &cmd->rccb, sizeof(*cmd),
+ &reply->rceb, sizeof(*reply));
+ if (result < 0)
+ goto error_cmd;
+ if (result < sizeof(*reply)) {
+ dev_err(&rc->uwb_dev.dev,
+ "DEV-ADDR-MGMT: not enough data replied: "
+ "%d vs %zu bytes needed\n", result, sizeof(*reply));
+ result = -ENOMSG;
+ } else if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "DEV-ADDR-MGMT: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply->bResultCode),
+ reply->bResultCode);
+ result = -EIO;
+ } else
+ result = 0;
+error_cmd:
+ kfree(cmd);
+error_kzalloc:
+ return result;
+}
+
+
+/**
+ * Set the UWB RC MAC or device address.
+ *
+ * @rc: UWB Radio Controller
+ * @_addr: Pointer to address to write [assumed to be either a
+ * 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *'].
+ * @type: Type of address to set (UWB_ADDR_DEV or UWB_ADDR_MAC).
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Some anal retentivity here: even if both 'struct
+ * uwb_{dev,mac}_addr' have the actual byte array in the same offset
+ * and I could just pass _addr to hwarc_cmd_dev_addr_mgmt(), I prefer
+ * to use some syntatic sugar in case someday we decide to change the
+ * format of the structs. The compiler will optimize it out anyway.
+ */
+static int uwb_rc_addr_set(struct uwb_rc *rc,
+ const void *_addr, enum uwb_addr_type type)
+{
+ int result;
+ u8 bmOperationType = 0x1; /* Set address */
+ const struct uwb_dev_addr *dev_addr = _addr;
+ const struct uwb_mac_addr *mac_addr = _addr;
+ struct uwb_rc_evt_dev_addr_mgmt reply;
+ const u8 *baAddr;
+
+ result = -EINVAL;
+ switch (type) {
+ case UWB_ADDR_DEV:
+ baAddr = dev_addr->data;
+ break;
+ case UWB_ADDR_MAC:
+ baAddr = mac_addr->data;
+ bmOperationType |= 0x2;
+ break;
+ default:
+ return result;
+ }
+ return uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &reply);
+}
+
+
+/**
+ * Get the UWB radio's MAC or device address.
+ *
+ * @rc: UWB Radio Controller
+ * @_addr: Where to write the address data [assumed to be either a
+ * 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *'].
+ * @type: Type of address to get (UWB_ADDR_DEV or UWB_ADDR_MAC).
+ * @returns: 0 if ok (and *_addr set), < 0 errno code on error.
+ *
+ * See comment in uwb_rc_addr_set() about anal retentivity in the
+ * type handling of the address variables.
+ */
+static int uwb_rc_addr_get(struct uwb_rc *rc,
+ void *_addr, enum uwb_addr_type type)
+{
+ int result;
+ u8 bmOperationType = 0x0; /* Get address */
+ struct uwb_rc_evt_dev_addr_mgmt evt;
+ struct uwb_dev_addr *dev_addr = _addr;
+ struct uwb_mac_addr *mac_addr = _addr;
+ u8 *baAddr;
+
+ result = -EINVAL;
+ switch (type) {
+ case UWB_ADDR_DEV:
+ baAddr = dev_addr->data;
+ break;
+ case UWB_ADDR_MAC:
+ bmOperationType |= 0x2;
+ baAddr = mac_addr->data;
+ break;
+ default:
+ return result;
+ }
+ result = uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &evt);
+ if (result == 0)
+ switch (type) {
+ case UWB_ADDR_DEV:
+ memcpy(&dev_addr->data, evt.baAddr,
+ sizeof(dev_addr->data));
+ break;
+ case UWB_ADDR_MAC:
+ memcpy(&mac_addr->data, evt.baAddr,
+ sizeof(mac_addr->data));
+ break;
+ default: /* shut gcc up */
+ BUG();
+ }
+ return result;
+}
+
+
+/** Get @rc's MAC address to @addr */
+int uwb_rc_mac_addr_get(struct uwb_rc *rc,
+ struct uwb_mac_addr *addr) {
+ return uwb_rc_addr_get(rc, addr, UWB_ADDR_MAC);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_mac_addr_get);
+
+
+/** Get @rc's device address to @addr */
+int uwb_rc_dev_addr_get(struct uwb_rc *rc,
+ struct uwb_dev_addr *addr) {
+ return uwb_rc_addr_get(rc, addr, UWB_ADDR_DEV);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_dev_addr_get);
+
+
+/** Set @rc's address to @addr */
+int uwb_rc_mac_addr_set(struct uwb_rc *rc,
+ const struct uwb_mac_addr *addr)
+{
+ int result = -EINVAL;
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = uwb_rc_addr_set(rc, addr, UWB_ADDR_MAC);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+
+/** Set @rc's address to @addr */
+int uwb_rc_dev_addr_set(struct uwb_rc *rc,
+ const struct uwb_dev_addr *addr)
+{
+ int result = -EINVAL;
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = uwb_rc_addr_set(rc, addr, UWB_ADDR_DEV);
+ rc->uwb_dev.dev_addr = *addr;
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+/* Returns !0 if given address is already assigned to device. */
+int __uwb_mac_addr_assigned_check(struct device *dev, void *_addr)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_mac_addr *addr = _addr;
+
+ if (!uwb_mac_addr_cmp(addr, &uwb_dev->mac_addr))
+ return !0;
+ return 0;
+}
+
+/* Returns !0 if given address is already assigned to device. */
+int __uwb_dev_addr_assigned_check(struct device *dev, void *_addr)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_dev_addr *addr = _addr;
+ if (!uwb_dev_addr_cmp(addr, &uwb_dev->dev_addr))
+ return !0;
+ return 0;
+}
+
+/**
+ * uwb_dev_addr_assign - assigned a generated DevAddr to a radio controller
+ * @rc: the (local) radio controller device requiring a new DevAddr
+ *
+ * A new DevAddr is required when:
+ * - first setting up a radio controller
+ * - if the hardware reports a DevAddr conflict
+ *
+ * The DevAddr is randomly generated in the generated DevAddr range
+ * [0x100, 0xfeff]. The number of devices in a beacon group is limited
+ * by mMaxBPLength (96) so this address space will never be exhausted.
+ *
+ * [ECMA-368] 17.1.1, 17.16.
+ */
+int uwb_rc_dev_addr_assign(struct uwb_rc *rc)
+{
+ struct uwb_dev_addr new_addr;
+
+ do {
+ get_random_bytes(new_addr.data, sizeof(new_addr.data));
+ } while (new_addr.data[0] == 0x00 || new_addr.data[0] == 0xff
+ || __uwb_dev_addr_assigned(rc, &new_addr));
+
+ return uwb_rc_dev_addr_set(rc, &new_addr);
+}
+
+/**
+ * uwbd_evt_handle_rc_dev_addr_conflict - handle a DEV_ADDR_CONFLICT event
+ * @evt: the DEV_ADDR_CONFLICT notification from the radio controller
+ *
+ * A new (non-conflicting) DevAddr is assigned to the radio controller.
+ *
+ * [ECMA-368] 17.1.1.1.
+ */
+int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt)
+{
+ struct uwb_rc *rc = evt->rc;
+
+ return uwb_rc_dev_addr_assign(rc);
+}
+
+/*
+ * Print the 48-bit EUI MAC address of the radio controller when
+ * reading /sys/class/uwb_rc/XX/mac_address
+ */
+static ssize_t uwb_rc_mac_addr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ struct uwb_mac_addr addr;
+ ssize_t result;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = uwb_rc_addr_get(rc, &addr, UWB_ADDR_MAC);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ if (result >= 0) {
+ result = uwb_mac_addr_print(buf, UWB_ADDR_STRSIZE, &addr);
+ buf[result++] = '\n';
+ }
+ return result;
+}
+
+/*
+ * Parse a 48 bit address written to /sys/class/uwb_rc/XX/mac_address
+ * and if correct, set it.
+ */
+static ssize_t uwb_rc_mac_addr_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ struct uwb_mac_addr addr;
+ ssize_t result;
+
+ if (!mac_pton(buf, addr.data))
+ return -EINVAL;
+ if (is_multicast_ether_addr(addr.data)) {
+ dev_err(&rc->uwb_dev.dev, "refusing to set multicast "
+ "MAC address %s\n", buf);
+ return -EINVAL;
+ }
+ result = uwb_rc_mac_addr_set(rc, &addr);
+ if (result == 0)
+ rc->uwb_dev.mac_addr = addr;
+
+ return result < 0 ? result : size;
+}
+DEVICE_ATTR(mac_address, S_IRUGO | S_IWUSR, uwb_rc_mac_addr_show, uwb_rc_mac_addr_store);
+
+/** Print @addr to @buf, @return bytes written */
+size_t __uwb_addr_print(char *buf, size_t buf_size, const unsigned char *addr,
+ int type)
+{
+ size_t result;
+ if (type)
+ result = scnprintf(buf, buf_size, "%pM", addr);
+ else
+ result = scnprintf(buf, buf_size, "%02x:%02x",
+ addr[1], addr[0]);
+ return result;
+}
+EXPORT_SYMBOL_GPL(__uwb_addr_print);
diff --git a/drivers/staging/uwb/allocator.c b/drivers/staging/uwb/allocator.c
new file mode 100644
index 000000000000..1f429fba20b7
--- /dev/null
+++ b/drivers/staging/uwb/allocator.c
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB reservation management.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "uwb.h"
+
+#include "uwb-internal.h"
+
+static void uwb_rsv_fill_column_alloc(struct uwb_rsv_alloc_info *ai)
+{
+ int col, mas, safe_mas, unsafe_mas;
+ unsigned char *bm = ai->bm;
+ struct uwb_rsv_col_info *ci = ai->ci;
+ unsigned char c;
+
+ for (col = ci->csi.start_col; col < UWB_NUM_ZONES; col += ci->csi.interval) {
+
+ safe_mas = ci->csi.safe_mas_per_col;
+ unsafe_mas = ci->csi.unsafe_mas_per_col;
+
+ for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++ ) {
+ if (bm[col * UWB_MAS_PER_ZONE + mas] == 0) {
+
+ if (safe_mas > 0) {
+ safe_mas--;
+ c = UWB_RSV_MAS_SAFE;
+ } else if (unsafe_mas > 0) {
+ unsafe_mas--;
+ c = UWB_RSV_MAS_UNSAFE;
+ } else {
+ break;
+ }
+ bm[col * UWB_MAS_PER_ZONE + mas] = c;
+ }
+ }
+ }
+}
+
+static void uwb_rsv_fill_row_alloc(struct uwb_rsv_alloc_info *ai)
+{
+ int mas, col, rows;
+ unsigned char *bm = ai->bm;
+ struct uwb_rsv_row_info *ri = &ai->ri;
+ unsigned char c;
+
+ rows = 1;
+ c = UWB_RSV_MAS_SAFE;
+ for (mas = UWB_MAS_PER_ZONE - 1; mas >= 0; mas--) {
+ if (ri->avail[mas] == 1) {
+
+ if (rows > ri->used_rows) {
+ break;
+ } else if (rows > 7) {
+ c = UWB_RSV_MAS_UNSAFE;
+ }
+
+ for (col = 0; col < UWB_NUM_ZONES; col++) {
+ if (bm[col * UWB_NUM_ZONES + mas] != UWB_RSV_MAS_NOT_AVAIL) {
+ bm[col * UWB_NUM_ZONES + mas] = c;
+ if(c == UWB_RSV_MAS_SAFE)
+ ai->safe_allocated_mases++;
+ else
+ ai->unsafe_allocated_mases++;
+ }
+ }
+ rows++;
+ }
+ }
+ ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases;
+}
+
+/*
+ * Find the best column set for a given availability, interval, num safe mas and
+ * num unsafe mas.
+ *
+ * The different sets are tried in order as shown below, depending on the interval.
+ *
+ * interval = 16
+ * deep = 0
+ * set 1 -> { 8 }
+ * deep = 1
+ * set 1 -> { 4 }
+ * set 2 -> { 12 }
+ * deep = 2
+ * set 1 -> { 2 }
+ * set 2 -> { 6 }
+ * set 3 -> { 10 }
+ * set 4 -> { 14 }
+ * deep = 3
+ * set 1 -> { 1 }
+ * set 2 -> { 3 }
+ * set 3 -> { 5 }
+ * set 4 -> { 7 }
+ * set 5 -> { 9 }
+ * set 6 -> { 11 }
+ * set 7 -> { 13 }
+ * set 8 -> { 15 }
+ *
+ * interval = 8
+ * deep = 0
+ * set 1 -> { 4 12 }
+ * deep = 1
+ * set 1 -> { 2 10 }
+ * set 2 -> { 6 14 }
+ * deep = 2
+ * set 1 -> { 1 9 }
+ * set 2 -> { 3 11 }
+ * set 3 -> { 5 13 }
+ * set 4 -> { 7 15 }
+ *
+ * interval = 4
+ * deep = 0
+ * set 1 -> { 2 6 10 14 }
+ * deep = 1
+ * set 1 -> { 1 5 9 13 }
+ * set 2 -> { 3 7 11 15 }
+ *
+ * interval = 2
+ * deep = 0
+ * set 1 -> { 1 3 5 7 9 11 13 15 }
+ */
+static int uwb_rsv_find_best_column_set(struct uwb_rsv_alloc_info *ai, int interval,
+ int num_safe_mas, int num_unsafe_mas)
+{
+ struct uwb_rsv_col_info *ci = ai->ci;
+ struct uwb_rsv_col_set_info *csi = &ci->csi;
+ struct uwb_rsv_col_set_info tmp_csi;
+ int deep, set, col, start_col_deep, col_start_set;
+ int start_col, max_mas_in_set, lowest_max_mas_in_deep;
+ int n_mas;
+ int found = UWB_RSV_ALLOC_NOT_FOUND;
+
+ tmp_csi.start_col = 0;
+ start_col_deep = interval;
+ n_mas = num_unsafe_mas + num_safe_mas;
+
+ for (deep = 0; ((interval >> deep) & 0x1) == 0; deep++) {
+ start_col_deep /= 2;
+ col_start_set = 0;
+ lowest_max_mas_in_deep = UWB_MAS_PER_ZONE;
+
+ for (set = 1; set <= (1 << deep); set++) {
+ max_mas_in_set = 0;
+ start_col = start_col_deep + col_start_set;
+ for (col = start_col; col < UWB_NUM_ZONES; col += interval) {
+
+ if (ci[col].max_avail_safe >= num_safe_mas &&
+ ci[col].max_avail_unsafe >= n_mas) {
+ if (ci[col].highest_mas[n_mas] > max_mas_in_set)
+ max_mas_in_set = ci[col].highest_mas[n_mas];
+ } else {
+ max_mas_in_set = 0;
+ break;
+ }
+ }
+ if ((lowest_max_mas_in_deep > max_mas_in_set) && max_mas_in_set) {
+ lowest_max_mas_in_deep = max_mas_in_set;
+
+ tmp_csi.start_col = start_col;
+ }
+ col_start_set += (interval >> deep);
+ }
+
+ if (lowest_max_mas_in_deep < 8) {
+ csi->start_col = tmp_csi.start_col;
+ found = UWB_RSV_ALLOC_FOUND;
+ break;
+ } else if ((lowest_max_mas_in_deep > 8) &&
+ (lowest_max_mas_in_deep != UWB_MAS_PER_ZONE) &&
+ (found == UWB_RSV_ALLOC_NOT_FOUND)) {
+ csi->start_col = tmp_csi.start_col;
+ found = UWB_RSV_ALLOC_FOUND;
+ }
+ }
+
+ if (found == UWB_RSV_ALLOC_FOUND) {
+ csi->interval = interval;
+ csi->safe_mas_per_col = num_safe_mas;
+ csi->unsafe_mas_per_col = num_unsafe_mas;
+
+ ai->safe_allocated_mases = (UWB_NUM_ZONES / interval) * num_safe_mas;
+ ai->unsafe_allocated_mases = (UWB_NUM_ZONES / interval) * num_unsafe_mas;
+ ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases;
+ ai->interval = interval;
+ }
+ return found;
+}
+
+static void get_row_descriptors(struct uwb_rsv_alloc_info *ai)
+{
+ unsigned char *bm = ai->bm;
+ struct uwb_rsv_row_info *ri = &ai->ri;
+ int col, mas;
+
+ ri->free_rows = 16;
+ for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) {
+ ri->avail[mas] = 1;
+ for (col = 1; col < UWB_NUM_ZONES; col++) {
+ if (bm[col * UWB_NUM_ZONES + mas] == UWB_RSV_MAS_NOT_AVAIL) {
+ ri->free_rows--;
+ ri->avail[mas]=0;
+ break;
+ }
+ }
+ }
+}
+
+static void uwb_rsv_fill_column_info(unsigned char *bm, int column, struct uwb_rsv_col_info *rci)
+{
+ int mas;
+ int block_count = 0, start_block = 0;
+ int previous_avail = 0;
+ int available = 0;
+ int safe_mas_in_row[UWB_MAS_PER_ZONE] = {
+ 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1,
+ };
+
+ rci->max_avail_safe = 0;
+
+ for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) {
+ if (!bm[column * UWB_NUM_ZONES + mas]) {
+ available++;
+ rci->max_avail_unsafe = available;
+
+ rci->highest_mas[available] = mas;
+
+ if (previous_avail) {
+ block_count++;
+ if ((block_count > safe_mas_in_row[start_block]) &&
+ (!rci->max_avail_safe))
+ rci->max_avail_safe = available - 1;
+ } else {
+ previous_avail = 1;
+ start_block = mas;
+ block_count = 1;
+ }
+ } else {
+ previous_avail = 0;
+ }
+ }
+ if (!rci->max_avail_safe)
+ rci->max_avail_safe = rci->max_avail_unsafe;
+}
+
+static void get_column_descriptors(struct uwb_rsv_alloc_info *ai)
+{
+ unsigned char *bm = ai->bm;
+ struct uwb_rsv_col_info *ci = ai->ci;
+ int col;
+
+ for (col = 1; col < UWB_NUM_ZONES; col++) {
+ uwb_rsv_fill_column_info(bm, col, &ci[col]);
+ }
+}
+
+static int uwb_rsv_find_best_row_alloc(struct uwb_rsv_alloc_info *ai)
+{
+ int n_rows;
+ int max_rows = ai->max_mas / UWB_USABLE_MAS_PER_ROW;
+ int min_rows = ai->min_mas / UWB_USABLE_MAS_PER_ROW;
+ if (ai->min_mas % UWB_USABLE_MAS_PER_ROW)
+ min_rows++;
+ for (n_rows = max_rows; n_rows >= min_rows; n_rows--) {
+ if (n_rows <= ai->ri.free_rows) {
+ ai->ri.used_rows = n_rows;
+ ai->interval = 1; /* row reservation */
+ uwb_rsv_fill_row_alloc(ai);
+ return UWB_RSV_ALLOC_FOUND;
+ }
+ }
+ return UWB_RSV_ALLOC_NOT_FOUND;
+}
+
+static int uwb_rsv_find_best_col_alloc(struct uwb_rsv_alloc_info *ai, int interval)
+{
+ int n_safe, n_unsafe, n_mas;
+ int n_column = UWB_NUM_ZONES / interval;
+ int max_per_zone = ai->max_mas / n_column;
+ int min_per_zone = ai->min_mas / n_column;
+
+ if (ai->min_mas % n_column)
+ min_per_zone++;
+
+ if (min_per_zone > UWB_MAS_PER_ZONE) {
+ return UWB_RSV_ALLOC_NOT_FOUND;
+ }
+
+ if (max_per_zone > UWB_MAS_PER_ZONE) {
+ max_per_zone = UWB_MAS_PER_ZONE;
+ }
+
+ for (n_mas = max_per_zone; n_mas >= min_per_zone; n_mas--) {
+ if (uwb_rsv_find_best_column_set(ai, interval, 0, n_mas) == UWB_RSV_ALLOC_NOT_FOUND)
+ continue;
+ for (n_safe = n_mas; n_safe >= 0; n_safe--) {
+ n_unsafe = n_mas - n_safe;
+ if (uwb_rsv_find_best_column_set(ai, interval, n_safe, n_unsafe) == UWB_RSV_ALLOC_FOUND) {
+ uwb_rsv_fill_column_alloc(ai);
+ return UWB_RSV_ALLOC_FOUND;
+ }
+ }
+ }
+ return UWB_RSV_ALLOC_NOT_FOUND;
+}
+
+int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *available,
+ struct uwb_mas_bm *result)
+{
+ struct uwb_rsv_alloc_info *ai;
+ int interval;
+ int bit_index;
+
+ ai = kzalloc(sizeof(struct uwb_rsv_alloc_info), GFP_KERNEL);
+ if (!ai)
+ return UWB_RSV_ALLOC_NOT_FOUND;
+ ai->min_mas = rsv->min_mas;
+ ai->max_mas = rsv->max_mas;
+ ai->max_interval = rsv->max_interval;
+
+
+ /* fill the not available vector from the available bm */
+ for_each_clear_bit(bit_index, available->bm, UWB_NUM_MAS)
+ ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL;
+
+ if (ai->max_interval == 1) {
+ get_row_descriptors(ai);
+ if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND)
+ goto alloc_found;
+ else
+ goto alloc_not_found;
+ }
+
+ get_column_descriptors(ai);
+
+ for (interval = 16; interval >= 2; interval>>=1) {
+ if (interval > ai->max_interval)
+ continue;
+ if (uwb_rsv_find_best_col_alloc(ai, interval) == UWB_RSV_ALLOC_FOUND)
+ goto alloc_found;
+ }
+
+ /* try row reservation if no column is found */
+ get_row_descriptors(ai);
+ if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND)
+ goto alloc_found;
+ else
+ goto alloc_not_found;
+
+ alloc_found:
+ bitmap_zero(result->bm, UWB_NUM_MAS);
+ bitmap_zero(result->unsafe_bm, UWB_NUM_MAS);
+ /* fill the safe and unsafe bitmaps */
+ for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) {
+ if (ai->bm[bit_index] == UWB_RSV_MAS_SAFE)
+ set_bit(bit_index, result->bm);
+ else if (ai->bm[bit_index] == UWB_RSV_MAS_UNSAFE)
+ set_bit(bit_index, result->unsafe_bm);
+ }
+ bitmap_or(result->bm, result->bm, result->unsafe_bm, UWB_NUM_MAS);
+
+ result->safe = ai->safe_allocated_mases;
+ result->unsafe = ai->unsafe_allocated_mases;
+
+ kfree(ai);
+ return UWB_RSV_ALLOC_FOUND;
+
+ alloc_not_found:
+ kfree(ai);
+ return UWB_RSV_ALLOC_NOT_FOUND;
+}
diff --git a/drivers/staging/uwb/beacon.c b/drivers/staging/uwb/beacon.c
new file mode 100644
index 000000000000..c483c19c5ef8
--- /dev/null
+++ b/drivers/staging/uwb/beacon.c
@@ -0,0 +1,595 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Beacon management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/slab.h>
+
+#include "uwb-internal.h"
+
+/* Start Beaconing command structure */
+struct uwb_rc_cmd_start_beacon {
+ struct uwb_rccb rccb;
+ __le16 wBPSTOffset;
+ u8 bChannelNumber;
+} __attribute__((packed));
+
+
+static int uwb_rc_start_beacon(struct uwb_rc *rc, u16 bpst_offset, u8 channel)
+{
+ int result;
+ struct uwb_rc_cmd_start_beacon *cmd;
+ struct uwb_rc_evt_confirm reply;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+ cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_START_BEACON);
+ cmd->wBPSTOffset = cpu_to_le16(bpst_offset);
+ cmd->bChannelNumber = channel;
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_START_BEACON;
+ result = uwb_rc_cmd(rc, "START-BEACON", &cmd->rccb, sizeof(*cmd),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "START-BEACON: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ }
+error_cmd:
+ kfree(cmd);
+ return result;
+}
+
+static int uwb_rc_stop_beacon(struct uwb_rc *rc)
+{
+ int result;
+ struct uwb_rccb *cmd;
+ struct uwb_rc_evt_confirm reply;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+ cmd->bCommandType = UWB_RC_CET_GENERAL;
+ cmd->wCommand = cpu_to_le16(UWB_RC_CMD_STOP_BEACON);
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_STOP_BEACON;
+ result = uwb_rc_cmd(rc, "STOP-BEACON", cmd, sizeof(*cmd),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "STOP-BEACON: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ }
+error_cmd:
+ kfree(cmd);
+ return result;
+}
+
+/*
+ * Start/stop beacons
+ *
+ * @rc: UWB Radio Controller to operate on
+ * @channel: UWB channel on which to beacon (WUSB[table
+ * 5-12]). If -1, stop beaconing.
+ * @bpst_offset: Beacon Period Start Time offset; FIXME-do zero
+ *
+ * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
+ * of a SET IE command after the device sent the first beacon that includes
+ * the IEs specified in the SET IE command. So, after we start beaconing we
+ * check if there is anything in the IE cache and call the SET IE command
+ * if needed.
+ */
+int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ dev_dbg(dev, "%s: channel = %d\n", __func__, channel);
+ if (channel < 0)
+ channel = -1;
+ if (channel == -1)
+ result = uwb_rc_stop_beacon(rc);
+ else {
+ /* channel >= 0...dah */
+ result = uwb_rc_start_beacon(rc, bpst_offset, channel);
+ if (result < 0) {
+ dev_err(dev, "Cannot start beaconing: %d\n", result);
+ return result;
+ }
+ if (le16_to_cpu(rc->ies->wIELength) > 0) {
+ result = uwb_rc_set_ie(rc, rc->ies);
+ if (result < 0) {
+ dev_err(dev, "Cannot set new IE on device: "
+ "%d\n", result);
+ result = uwb_rc_stop_beacon(rc);
+ channel = -1;
+ bpst_offset = 0;
+ }
+ }
+ }
+
+ if (result >= 0)
+ rc->beaconing = channel;
+ return result;
+}
+
+/*
+ * Beacon cache
+ *
+ * The purpose of this is to speed up the lookup of becon information
+ * when a new beacon arrives. The UWB Daemon uses it also to keep a
+ * tab of which devices are in radio distance and which not. When a
+ * device's beacon stays present for more than a certain amount of
+ * time, it is considered a new, usable device. When a beacon ceases
+ * to be received for a certain amount of time, it is considered that
+ * the device is gone.
+ *
+ * FIXME: use an allocator for the entries
+ * FIXME: use something faster for search than a list
+ */
+
+void uwb_bce_kfree(struct kref *_bce)
+{
+ struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt);
+
+ kfree(bce->be);
+ kfree(bce);
+}
+
+
+/* Find a beacon by dev addr in the cache */
+static
+struct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc,
+ const struct uwb_dev_addr *dev_addr)
+{
+ struct uwb_beca_e *bce, *next;
+ list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
+ if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr)))
+ goto out;
+ }
+ bce = NULL;
+out:
+ return bce;
+}
+
+/* Find a beacon by dev addr in the cache */
+static
+struct uwb_beca_e *__uwb_beca_find_bymac(struct uwb_rc *rc,
+ const struct uwb_mac_addr *mac_addr)
+{
+ struct uwb_beca_e *bce, *next;
+ list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
+ if (!memcmp(bce->mac_addr, mac_addr->data,
+ sizeof(struct uwb_mac_addr)))
+ goto out;
+ }
+ bce = NULL;
+out:
+ return bce;
+}
+
+/**
+ * uwb_dev_get_by_devaddr - get a UWB device with a specific DevAddr
+ * @rc: the radio controller that saw the device
+ * @devaddr: DevAddr of the UWB device to find
+ *
+ * There may be more than one matching device (in the case of a
+ * DevAddr conflict), but only the first one is returned.
+ */
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+ const struct uwb_dev_addr *devaddr)
+{
+ struct uwb_dev *found = NULL;
+ struct uwb_beca_e *bce;
+
+ mutex_lock(&rc->uwb_beca.mutex);
+ bce = __uwb_beca_find_bydev(rc, devaddr);
+ if (bce)
+ found = uwb_dev_try_get(rc, bce->uwb_dev);
+ mutex_unlock(&rc->uwb_beca.mutex);
+
+ return found;
+}
+
+/**
+ * uwb_dev_get_by_macaddr - get a UWB device with a specific EUI-48
+ * @rc: the radio controller that saw the device
+ * @devaddr: EUI-48 of the UWB device to find
+ */
+struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
+ const struct uwb_mac_addr *macaddr)
+{
+ struct uwb_dev *found = NULL;
+ struct uwb_beca_e *bce;
+
+ mutex_lock(&rc->uwb_beca.mutex);
+ bce = __uwb_beca_find_bymac(rc, macaddr);
+ if (bce)
+ found = uwb_dev_try_get(rc, bce->uwb_dev);
+ mutex_unlock(&rc->uwb_beca.mutex);
+
+ return found;
+}
+
+/* Initialize a beacon cache entry */
+static void uwb_beca_e_init(struct uwb_beca_e *bce)
+{
+ mutex_init(&bce->mutex);
+ kref_init(&bce->refcnt);
+ stats_init(&bce->lqe_stats);
+ stats_init(&bce->rssi_stats);
+}
+
+/*
+ * Add a beacon to the cache
+ *
+ * @be: Beacon event information
+ * @bf: Beacon frame (part of b, really)
+ * @ts_jiffies: Timestamp (in jiffies) when the beacon was received
+ */
+static
+struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc,
+ struct uwb_rc_evt_beacon *be,
+ struct uwb_beacon_frame *bf,
+ unsigned long ts_jiffies)
+{
+ struct uwb_beca_e *bce;
+
+ bce = kzalloc(sizeof(*bce), GFP_KERNEL);
+ if (bce == NULL)
+ return NULL;
+ uwb_beca_e_init(bce);
+ bce->ts_jiffies = ts_jiffies;
+ bce->uwb_dev = NULL;
+ list_add(&bce->node, &rc->uwb_beca.list);
+ return bce;
+}
+
+/*
+ * Wipe out beacon entries that became stale
+ *
+ * Remove associated devicest too.
+ */
+void uwb_beca_purge(struct uwb_rc *rc)
+{
+ struct uwb_beca_e *bce, *next;
+ unsigned long expires;
+
+ mutex_lock(&rc->uwb_beca.mutex);
+ list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
+ expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms);
+ if (time_after(jiffies, expires)) {
+ uwbd_dev_offair(bce);
+ }
+ }
+ mutex_unlock(&rc->uwb_beca.mutex);
+}
+
+/* Clean up the whole beacon cache. Called on shutdown */
+void uwb_beca_release(struct uwb_rc *rc)
+{
+ struct uwb_beca_e *bce, *next;
+
+ mutex_lock(&rc->uwb_beca.mutex);
+ list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
+ list_del(&bce->node);
+ uwb_bce_put(bce);
+ }
+ mutex_unlock(&rc->uwb_beca.mutex);
+}
+
+static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be,
+ struct uwb_beacon_frame *bf)
+{
+ char macbuf[UWB_ADDR_STRSIZE];
+ char devbuf[UWB_ADDR_STRSIZE];
+ char dstbuf[UWB_ADDR_STRSIZE];
+
+ uwb_mac_addr_print(macbuf, sizeof(macbuf), &bf->Device_Identifier);
+ uwb_dev_addr_print(devbuf, sizeof(devbuf), &bf->hdr.SrcAddr);
+ uwb_dev_addr_print(dstbuf, sizeof(dstbuf), &bf->hdr.DestAddr);
+ dev_info(&rc->uwb_dev.dev,
+ "BEACON from %s to %s (ch%u offset %u slot %u MAC %s)\n",
+ devbuf, dstbuf, be->bChannelNumber, be->wBPSTOffset,
+ bf->Beacon_Slot_Number, macbuf);
+}
+
+/*
+ * @bce: beacon cache entry, referenced
+ */
+ssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce,
+ char *buf, size_t size)
+{
+ ssize_t result = 0;
+ struct uwb_rc_evt_beacon *be;
+ struct uwb_beacon_frame *bf;
+ int ies_len;
+ struct uwb_ie_hdr *ies;
+
+ mutex_lock(&bce->mutex);
+
+ be = bce->be;
+ if (be) {
+ bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
+ ies_len = be->wBeaconInfoLength - sizeof(struct uwb_beacon_frame);
+ ies = (struct uwb_ie_hdr *)bf->IEData;
+
+ result = uwb_ie_dump_hex(ies, ies_len, buf, size);
+ }
+
+ mutex_unlock(&bce->mutex);
+
+ return result;
+}
+
+/*
+ * Verify that the beacon event, frame and IEs are ok
+ */
+static int uwb_verify_beacon(struct uwb_rc *rc, struct uwb_event *evt,
+ struct uwb_rc_evt_beacon *be)
+{
+ int result = -EINVAL;
+ struct uwb_beacon_frame *bf;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ /* Is there enough data to decode a beacon frame? */
+ if (evt->notif.size < sizeof(*be) + sizeof(*bf)) {
+ dev_err(dev, "BEACON event: Not enough data to decode "
+ "(%zu vs %zu bytes needed)\n", evt->notif.size,
+ sizeof(*be) + sizeof(*bf));
+ goto error;
+ }
+ /* FIXME: make sure beacon frame IEs are fine and that the whole thing
+ * is consistent */
+ result = 0;
+error:
+ return result;
+}
+
+/*
+ * Handle UWB_RC_EVT_BEACON events
+ *
+ * We check the beacon cache to see how the received beacon fares. If
+ * is there already we refresh the timestamp. If not we create a new
+ * entry.
+ *
+ * According to the WHCI and WUSB specs, only one beacon frame is
+ * allowed per notification block, so we don't bother about scanning
+ * for more.
+ */
+int uwbd_evt_handle_rc_beacon(struct uwb_event *evt)
+{
+ int result = -EINVAL;
+ struct uwb_rc *rc;
+ struct uwb_rc_evt_beacon *be;
+ struct uwb_beacon_frame *bf;
+ struct uwb_beca_e *bce;
+
+ rc = evt->rc;
+ be = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon, rceb);
+ result = uwb_verify_beacon(rc, evt, be);
+ if (result < 0)
+ return result;
+
+ /* FIXME: handle alien beacons. */
+ if (be->bBeaconType == UWB_RC_BEACON_TYPE_OL_ALIEN ||
+ be->bBeaconType == UWB_RC_BEACON_TYPE_NOL_ALIEN) {
+ return -ENOSYS;
+ }
+
+ bf = (struct uwb_beacon_frame *) be->BeaconInfo;
+
+ /*
+ * Drop beacons from devices with a NULL EUI-48 -- they cannot
+ * be uniquely identified.
+ *
+ * It's expected that these will all be WUSB devices and they
+ * have a WUSB specific connection method so ignoring them
+ * here shouldn't be a problem.
+ */
+ if (uwb_mac_addr_bcast(&bf->Device_Identifier))
+ return 0;
+
+ mutex_lock(&rc->uwb_beca.mutex);
+ bce = __uwb_beca_find_bymac(rc, &bf->Device_Identifier);
+ if (bce == NULL) {
+ /* Not in there, a new device is pinging */
+ uwb_beacon_print(evt->rc, be, bf);
+ bce = __uwb_beca_add(rc, be, bf, evt->ts_jiffies);
+ if (bce == NULL) {
+ mutex_unlock(&rc->uwb_beca.mutex);
+ return -ENOMEM;
+ }
+ }
+ mutex_unlock(&rc->uwb_beca.mutex);
+
+ mutex_lock(&bce->mutex);
+ /* purge old beacon data */
+ kfree(bce->be);
+
+ /* Update commonly used fields */
+ bce->ts_jiffies = evt->ts_jiffies;
+ bce->be = be;
+ bce->dev_addr = bf->hdr.SrcAddr;
+ bce->mac_addr = &bf->Device_Identifier;
+ be->wBPSTOffset = le16_to_cpu(be->wBPSTOffset);
+ be->wBeaconInfoLength = le16_to_cpu(be->wBeaconInfoLength);
+ stats_add_sample(&bce->lqe_stats, be->bLQI - 7);
+ stats_add_sample(&bce->rssi_stats, be->bRSSI + 18);
+
+ /*
+ * This might be a beacon from a new device.
+ */
+ if (bce->uwb_dev == NULL)
+ uwbd_dev_onair(evt->rc, bce);
+
+ mutex_unlock(&bce->mutex);
+
+ return 1; /* we keep the event data */
+}
+
+/*
+ * Handle UWB_RC_EVT_BEACON_SIZE events
+ *
+ * XXXXX
+ */
+int uwbd_evt_handle_rc_beacon_size(struct uwb_event *evt)
+{
+ int result = -EINVAL;
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc_evt_beacon_size *bs;
+
+ /* Is there enough data to decode the event? */
+ if (evt->notif.size < sizeof(*bs)) {
+ dev_err(dev, "BEACON SIZE notification: Not enough data to "
+ "decode (%zu vs %zu bytes needed)\n",
+ evt->notif.size, sizeof(*bs));
+ goto error;
+ }
+ bs = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon_size, rceb);
+ if (0)
+ dev_info(dev, "Beacon size changed to %u bytes "
+ "(FIXME: action?)\n", le16_to_cpu(bs->wNewBeaconSize));
+ else {
+ /* temporary hack until we do something with this message... */
+ static unsigned count;
+ if (++count % 1000 == 0)
+ dev_info(dev, "Beacon size changed %u times "
+ "(FIXME: action?)\n", count);
+ }
+ result = 0;
+error:
+ return result;
+}
+
+/**
+ * uwbd_evt_handle_rc_bp_slot_change - handle a BP_SLOT_CHANGE event
+ * @evt: the BP_SLOT_CHANGE notification from the radio controller
+ *
+ * If the event indicates that no beacon period slots were available
+ * then radio controller has transitioned to a non-beaconing state.
+ * Otherwise, simply save the current beacon slot.
+ */
+int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *evt)
+{
+ struct uwb_rc *rc = evt->rc;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_evt_bp_slot_change *bpsc;
+
+ if (evt->notif.size < sizeof(*bpsc)) {
+ dev_err(dev, "BP SLOT CHANGE event: Not enough data\n");
+ return -EINVAL;
+ }
+ bpsc = container_of(evt->notif.rceb, struct uwb_rc_evt_bp_slot_change, rceb);
+
+ if (uwb_rc_evt_bp_slot_change_no_slot(bpsc)) {
+ dev_err(dev, "stopped beaconing: No free slots in BP\n");
+ mutex_lock(&rc->uwb_dev.mutex);
+ rc->beaconing = -1;
+ mutex_unlock(&rc->uwb_dev.mutex);
+ } else
+ rc->uwb_dev.beacon_slot = uwb_rc_evt_bp_slot_change_slot_num(bpsc);
+
+ return 0;
+}
+
+/**
+ * Handle UWB_RC_EVT_BPOIE_CHANGE events
+ *
+ * XXXXX
+ */
+struct uwb_ie_bpo {
+ struct uwb_ie_hdr hdr;
+ u8 bp_length;
+ u8 data[];
+} __attribute__((packed));
+
+int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt)
+{
+ int result = -EINVAL;
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc_evt_bpoie_change *bpoiec;
+ struct uwb_ie_bpo *bpoie;
+ static unsigned count; /* FIXME: this is a temp hack */
+ size_t iesize;
+
+ /* Is there enough data to decode it? */
+ if (evt->notif.size < sizeof(*bpoiec)) {
+ dev_err(dev, "BPOIEC notification: Not enough data to "
+ "decode (%zu vs %zu bytes needed)\n",
+ evt->notif.size, sizeof(*bpoiec));
+ goto error;
+ }
+ bpoiec = container_of(evt->notif.rceb, struct uwb_rc_evt_bpoie_change, rceb);
+ iesize = le16_to_cpu(bpoiec->wBPOIELength);
+ if (iesize < sizeof(*bpoie)) {
+ dev_err(dev, "BPOIEC notification: Not enough IE data to "
+ "decode (%zu vs %zu bytes needed)\n",
+ iesize, sizeof(*bpoie));
+ goto error;
+ }
+ if (++count % 1000 == 0) /* Lame placeholder */
+ dev_info(dev, "BPOIE: %u changes received\n", count);
+ /*
+ * FIXME: At this point we should go over all the IEs in the
+ * bpoiec->BPOIE array and act on each.
+ */
+ result = 0;
+error:
+ return result;
+}
+
+/*
+ * Print beaconing state.
+ */
+static ssize_t uwb_rc_beacon_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ ssize_t result;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = sprintf(buf, "%d\n", rc->beaconing);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+/*
+ * Start beaconing on the specified channel, or stop beaconing.
+ */
+static ssize_t uwb_rc_beacon_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ int channel;
+ ssize_t result = -EINVAL;
+
+ result = sscanf(buf, "%d", &channel);
+ if (result >= 1)
+ result = uwb_radio_force_channel(rc, channel);
+
+ return result < 0 ? result : size;
+}
+DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, uwb_rc_beacon_show, uwb_rc_beacon_store);
diff --git a/drivers/staging/uwb/driver.c b/drivers/staging/uwb/driver.c
new file mode 100644
index 000000000000..5755c2e49ffc
--- /dev/null
+++ b/drivers/staging/uwb/driver.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Driver initialization, etc
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ *
+ * Life cycle: FIXME: explain
+ *
+ * UWB radio controller:
+ *
+ * 1. alloc a uwb_rc, zero it
+ * 2. call uwb_rc_init() on it to set it up + ops (won't do any
+ * kind of allocation)
+ * 3. register (now it is owned by the UWB stack--deregister before
+ * freeing/destroying).
+ * 4. It lives on it's own now (UWB stack handles)--when it
+ * disconnects, call unregister()
+ * 5. free it.
+ *
+ * Make sure you have a reference to the uwb_rc before calling
+ * any of the UWB API functions.
+ *
+ * TODO:
+ *
+ * 1. Locking and life cycle management is crappy still. All entry
+ * points to the UWB HCD API assume you have a reference on the
+ * uwb_rc structure and that it won't go away. They mutex lock it
+ * before doing anything.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/random.h>
+
+#include "uwb-internal.h"
+
+
+/* UWB stack attributes (or 'global' constants) */
+
+
+/**
+ * If a beacon disappears for longer than this, then we consider the
+ * device who was represented by that beacon to be gone.
+ *
+ * ECMA-368[17.2.3, last para] establishes that a device must not
+ * consider a device to be its neighbour if he doesn't receive a beacon
+ * for more than mMaxLostBeacons. mMaxLostBeacons is defined in
+ * ECMA-368[17.16] as 3; because we can get only one beacon per
+ * superframe, that'd be 3 * 65ms = 195 ~ 200 ms. Let's give it time
+ * for jitter and stuff and make it 500 ms.
+ */
+unsigned long beacon_timeout_ms = 500;
+
+static
+ssize_t beacon_timeout_ms_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms);
+}
+
+static
+ssize_t beacon_timeout_ms_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long bt;
+ ssize_t result;
+ result = sscanf(buf, "%lu", &bt);
+ if (result != 1)
+ return -EINVAL;
+ beacon_timeout_ms = bt;
+ return size;
+}
+static CLASS_ATTR_RW(beacon_timeout_ms);
+
+static struct attribute *uwb_class_attrs[] = {
+ &class_attr_beacon_timeout_ms.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(uwb_class);
+
+/** Device model classes */
+struct class uwb_rc_class = {
+ .name = "uwb_rc",
+ .class_groups = uwb_class_groups,
+};
+
+
+static int __init uwb_subsys_init(void)
+{
+ int result = 0;
+
+ result = uwb_est_create();
+ if (result < 0) {
+ printk(KERN_ERR "uwb: Can't initialize EST subsystem\n");
+ goto error_est_init;
+ }
+
+ result = class_register(&uwb_rc_class);
+ if (result < 0)
+ goto error_uwb_rc_class_register;
+
+ /* Register the UWB bus */
+ result = bus_register(&uwb_bus_type);
+ if (result) {
+ pr_err("%s - registering bus driver failed\n", __func__);
+ goto exit_bus;
+ }
+
+ uwb_dbg_init();
+ return 0;
+
+exit_bus:
+ class_unregister(&uwb_rc_class);
+error_uwb_rc_class_register:
+ uwb_est_destroy();
+error_est_init:
+ return result;
+}
+module_init(uwb_subsys_init);
+
+static void __exit uwb_subsys_exit(void)
+{
+ uwb_dbg_exit();
+ bus_unregister(&uwb_bus_type);
+ class_unregister(&uwb_rc_class);
+ uwb_est_destroy();
+ return;
+}
+module_exit(uwb_subsys_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Ultra Wide Band core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/drp-avail.c b/drivers/staging/uwb/drp-avail.c
new file mode 100644
index 000000000000..02392ab82a7d
--- /dev/null
+++ b/drivers/staging/uwb/drp-avail.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * DRP availability management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Reinette Chatre <reinette.chatre@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * Manage DRP Availability (the MAS available for DRP
+ * reservations). Thus:
+ *
+ * - Handle DRP Availability Change notifications
+ *
+ * - Allow the reservation manager to indicate MAS reserved/released
+ * by local (owned by/targeted at the radio controller)
+ * reservations.
+ *
+ * - Based on the two sources above, generate a DRP Availability IE to
+ * be included in the beacon.
+ *
+ * See also the documentation for struct uwb_drp_avail.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/bitmap.h>
+#include "uwb-internal.h"
+
+/**
+ * uwb_drp_avail_init - initialize an RC's MAS availability
+ *
+ * All MAS are available initially. The RC will inform use which
+ * slots are used for the BP (it may change in size).
+ */
+void uwb_drp_avail_init(struct uwb_rc *rc)
+{
+ bitmap_fill(rc->drp_avail.global, UWB_NUM_MAS);
+ bitmap_fill(rc->drp_avail.local, UWB_NUM_MAS);
+ bitmap_fill(rc->drp_avail.pending, UWB_NUM_MAS);
+}
+
+/*
+ * Determine MAS available for new local reservations.
+ *
+ * avail = global & local & pending
+ */
+void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail)
+{
+ bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
+ bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS);
+}
+
+/**
+ * uwb_drp_avail_reserve_pending - reserve MAS for a new reservation
+ * @rc: the radio controller
+ * @mas: the MAS to reserve
+ *
+ * Returns 0 on success, or -EBUSY if the MAS requested aren't available.
+ */
+int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas)
+{
+ struct uwb_mas_bm avail;
+
+ uwb_drp_available(rc, &avail);
+ if (!bitmap_subset(mas->bm, avail.bm, UWB_NUM_MAS))
+ return -EBUSY;
+
+ bitmap_andnot(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
+ return 0;
+}
+
+/**
+ * uwb_drp_avail_reserve - reserve MAS for an established reservation
+ * @rc: the radio controller
+ * @mas: the MAS to reserve
+ */
+void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas)
+{
+ bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
+ bitmap_andnot(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS);
+ rc->drp_avail.ie_valid = false;
+}
+
+/**
+ * uwb_drp_avail_release - release MAS from a pending or established reservation
+ * @rc: the radio controller
+ * @mas: the MAS to release
+ */
+void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas)
+{
+ bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS);
+ bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
+ rc->drp_avail.ie_valid = false;
+ uwb_rsv_handle_drp_avail_change(rc);
+}
+
+/**
+ * uwb_drp_avail_ie_update - update the DRP Availability IE
+ * @rc: the radio controller
+ *
+ * avail = global & local
+ */
+void uwb_drp_avail_ie_update(struct uwb_rc *rc)
+{
+ struct uwb_mas_bm avail;
+
+ bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
+
+ rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY;
+ rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8;
+ uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail);
+ rc->drp_avail.ie_valid = true;
+}
+
+/**
+ * Create an unsigned long from a buffer containing a byte stream.
+ *
+ * @array: pointer to buffer
+ * @itr: index of buffer from where we start
+ * @len: the buffer's remaining size may not be exact multiple of
+ * sizeof(unsigned long), @len is the length of buffer that needs
+ * to be converted. This will be sizeof(unsigned long) or smaller
+ * (BUG if not). If it is smaller then we will pad the remaining
+ * space of the result with zeroes.
+ */
+static
+unsigned long get_val(u8 *array, size_t itr, size_t len)
+{
+ unsigned long val = 0;
+ size_t top = itr + len;
+
+ BUG_ON(len > sizeof(val));
+
+ while (itr < top) {
+ val <<= 8;
+ val |= array[top - 1];
+ top--;
+ }
+ val <<= 8 * (sizeof(val) - len); /* padding */
+ return val;
+}
+
+/**
+ * Initialize bitmap from data buffer.
+ *
+ * The bitmap to be converted could come from a IE, for example a
+ * DRP Availability IE.
+ * From ECMA-368 1.0 [16.8.7]: "
+ * octets: 1 1 N * (0 to 32)
+ * Element ID Length (=N) DRP Availability Bitmap
+ *
+ * The DRP Availability Bitmap field is up to 256 bits long, one
+ * bit for each MAS in the superframe, where the least-significant
+ * bit of the field corresponds to the first MAS in the superframe
+ * and successive bits correspond to successive MASs."
+ *
+ * The DRP Availability bitmap is in octets from 0 to 32, so octet
+ * 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32
+ * octets, the bits in octets not included at the end of the bitmap are
+ * treated as zero. In this case (when the bitmap is smaller than 32
+ * octets) the MAS represented range from MAS 1 to MAS (size of bitmap)
+ * with the last octet still containing bits for MAS 1-8, etc.
+ *
+ * For example:
+ * F00F0102 03040506 0708090A 0B0C0D0E 0F010203
+ * ^^^^
+ * ||||
+ * ||||
+ * |||\LSB of byte is MAS 9
+ * ||\MSB of byte is MAS 16
+ * |\LSB of first byte is MAS 1
+ * \ MSB of byte is MAS 8
+ *
+ * An example of this encoding can be found in ECMA-368 Annex-D [Table D.11]
+ *
+ * The resulting bitmap will have the following mapping:
+ * bit position 0 == MAS 1
+ * bit position 1 == MAS 2
+ * ...
+ * bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS
+ *
+ * @bmp_itr: pointer to bitmap (can be declared with DECLARE_BITMAP)
+ * @buffer: pointer to buffer containing bitmap data in big endian
+ * format (MSB first)
+ * @buffer_size:number of bytes with which bitmap should be initialized
+ */
+static
+void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer,
+ size_t buffer_size)
+{
+ u8 *buffer = _buffer;
+ size_t itr, len;
+ unsigned long val;
+
+ itr = 0;
+ while (itr < buffer_size) {
+ len = buffer_size - itr >= sizeof(val) ?
+ sizeof(val) : buffer_size - itr;
+ val = get_val(buffer, itr, len);
+ bmp_itr[itr / sizeof(val)] = val;
+ itr += sizeof(val);
+ }
+}
+
+
+/**
+ * Extract DRP Availability bitmap from the notification.
+ *
+ * The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes
+ * We convert that to our internal representation.
+ */
+static
+int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp)
+{
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc_evt_drp_avail *drp_evt;
+ int result = -EINVAL;
+
+ /* Is there enough data to decode the event? */
+ if (evt->notif.size < sizeof(*drp_evt)) {
+ dev_err(dev, "DRP Availability Change: Not enough "
+ "data to decode event [%zu bytes, %zu "
+ "needed]\n", evt->notif.size, sizeof(*drp_evt));
+ goto error;
+ }
+ drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb);
+ buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8);
+ result = 0;
+error:
+ return result;
+}
+
+
+/**
+ * Process an incoming DRP Availability notification.
+ *
+ * @evt: Event information (packs the actual event data, which
+ * radio controller it came to, etc).
+ *
+ * @returns: 0 on success (so uwbd() frees the event buffer), < 0
+ * on error.
+ *
+ * According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that
+ * the MAS slot is available, bits set to ZERO indicate that the slot
+ * is busy.
+ *
+ * So we clear available slots, we set used slots :)
+ *
+ * The notification only marks non-availability based on the BP and
+ * received DRP IEs that are not for this radio controller. A copy of
+ * this bitmap is needed to generate the real availability (which
+ * includes local and pending reservations).
+ *
+ * The DRP Availability IE that this radio controller emits will need
+ * to be updated.
+ */
+int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt)
+{
+ int result;
+ struct uwb_rc *rc = evt->rc;
+ DECLARE_BITMAP(bmp, UWB_NUM_MAS);
+
+ result = uwbd_evt_get_drp_avail(evt, bmp);
+ if (result < 0)
+ return result;
+
+ mutex_lock(&rc->rsvs_mutex);
+ bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS);
+ rc->drp_avail.ie_valid = false;
+ uwb_rsv_handle_drp_avail_change(rc);
+ mutex_unlock(&rc->rsvs_mutex);
+
+ uwb_rsv_sched_update(rc);
+
+ return 0;
+}
diff --git a/drivers/staging/uwb/drp-ie.c b/drivers/staging/uwb/drp-ie.c
new file mode 100644
index 000000000000..b2a862cf76de
--- /dev/null
+++ b/drivers/staging/uwb/drp-ie.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB DRP IE management.
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+
+#include "uwb.h"
+#include "uwb-internal.h"
+
+
+/*
+ * Return the reason code for a reservations's DRP IE.
+ */
+static int uwb_rsv_reason_code(struct uwb_rsv *rsv)
+{
+ static const int reason_codes[] = {
+ [UWB_RSV_STATE_O_INITIATED] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_O_PENDING] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_O_MODIFIED] = UWB_DRP_REASON_MODIFIED,
+ [UWB_RSV_STATE_O_ESTABLISHED] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_O_TO_BE_MOVED] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_O_MOVE_COMBINING] = UWB_DRP_REASON_MODIFIED,
+ [UWB_RSV_STATE_O_MOVE_REDUCING] = UWB_DRP_REASON_MODIFIED,
+ [UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_T_ACCEPTED] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_T_CONFLICT] = UWB_DRP_REASON_CONFLICT,
+ [UWB_RSV_STATE_T_PENDING] = UWB_DRP_REASON_PENDING,
+ [UWB_RSV_STATE_T_DENIED] = UWB_DRP_REASON_DENIED,
+ [UWB_RSV_STATE_T_RESIZED] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT,
+ [UWB_RSV_STATE_T_EXPANDING_PENDING] = UWB_DRP_REASON_PENDING,
+ [UWB_RSV_STATE_T_EXPANDING_DENIED] = UWB_DRP_REASON_DENIED,
+ };
+
+ return reason_codes[rsv->state];
+}
+
+/*
+ * Return the reason code for a reservations's companion DRP IE .
+ */
+static int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv)
+{
+ static const int companion_reason_codes[] = {
+ [UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED,
+ [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT,
+ [UWB_RSV_STATE_T_EXPANDING_PENDING] = UWB_DRP_REASON_PENDING,
+ [UWB_RSV_STATE_T_EXPANDING_DENIED] = UWB_DRP_REASON_DENIED,
+ };
+
+ return companion_reason_codes[rsv->state];
+}
+
+/*
+ * Return the status bit for a reservations's DRP IE.
+ */
+int uwb_rsv_status(struct uwb_rsv *rsv)
+{
+ static const int statuses[] = {
+ [UWB_RSV_STATE_O_INITIATED] = 0,
+ [UWB_RSV_STATE_O_PENDING] = 0,
+ [UWB_RSV_STATE_O_MODIFIED] = 1,
+ [UWB_RSV_STATE_O_ESTABLISHED] = 1,
+ [UWB_RSV_STATE_O_TO_BE_MOVED] = 0,
+ [UWB_RSV_STATE_O_MOVE_COMBINING] = 1,
+ [UWB_RSV_STATE_O_MOVE_REDUCING] = 1,
+ [UWB_RSV_STATE_O_MOVE_EXPANDING] = 1,
+ [UWB_RSV_STATE_T_ACCEPTED] = 1,
+ [UWB_RSV_STATE_T_CONFLICT] = 0,
+ [UWB_RSV_STATE_T_PENDING] = 0,
+ [UWB_RSV_STATE_T_DENIED] = 0,
+ [UWB_RSV_STATE_T_RESIZED] = 1,
+ [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1,
+ [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 1,
+ [UWB_RSV_STATE_T_EXPANDING_PENDING] = 1,
+ [UWB_RSV_STATE_T_EXPANDING_DENIED] = 1,
+
+ };
+
+ return statuses[rsv->state];
+}
+
+/*
+ * Return the status bit for a reservations's companion DRP IE .
+ */
+int uwb_rsv_companion_status(struct uwb_rsv *rsv)
+{
+ static const int companion_statuses[] = {
+ [UWB_RSV_STATE_O_MOVE_EXPANDING] = 0,
+ [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1,
+ [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 0,
+ [UWB_RSV_STATE_T_EXPANDING_PENDING] = 0,
+ [UWB_RSV_STATE_T_EXPANDING_DENIED] = 0,
+ };
+
+ return companion_statuses[rsv->state];
+}
+
+/*
+ * Allocate a DRP IE.
+ *
+ * To save having to free/allocate a DRP IE when its MAS changes,
+ * enough memory is allocated for the maxiumum number of DRP
+ * allocation fields. This gives an overhead per reservation of up to
+ * (UWB_NUM_ZONES - 1) * 4 = 60 octets.
+ */
+static struct uwb_ie_drp *uwb_drp_ie_alloc(void)
+{
+ struct uwb_ie_drp *drp_ie;
+
+ drp_ie = kzalloc(struct_size(drp_ie, allocs, UWB_NUM_ZONES),
+ GFP_KERNEL);
+ if (drp_ie)
+ drp_ie->hdr.element_id = UWB_IE_DRP;
+ return drp_ie;
+}
+
+
+/*
+ * Fill a DRP IE's allocation fields from a MAS bitmap.
+ */
+static void uwb_drp_ie_from_bm(struct uwb_ie_drp *drp_ie,
+ struct uwb_mas_bm *mas)
+{
+ int z, i, num_fields = 0, next = 0;
+ struct uwb_drp_alloc *zones;
+ __le16 current_bmp;
+ DECLARE_BITMAP(tmp_bmp, UWB_NUM_MAS);
+ DECLARE_BITMAP(tmp_mas_bm, UWB_MAS_PER_ZONE);
+
+ zones = drp_ie->allocs;
+
+ bitmap_copy(tmp_bmp, mas->bm, UWB_NUM_MAS);
+
+ /* Determine unique MAS bitmaps in zones from bitmap. */
+ for (z = 0; z < UWB_NUM_ZONES; z++) {
+ bitmap_copy(tmp_mas_bm, tmp_bmp, UWB_MAS_PER_ZONE);
+ if (bitmap_weight(tmp_mas_bm, UWB_MAS_PER_ZONE) > 0) {
+ bool found = false;
+ current_bmp = (__le16) *tmp_mas_bm;
+ for (i = 0; i < next; i++) {
+ if (current_bmp == zones[i].mas_bm) {
+ zones[i].zone_bm |= 1 << z;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ num_fields++;
+ zones[next].zone_bm = 1 << z;
+ zones[next].mas_bm = current_bmp;
+ next++;
+ }
+ }
+ bitmap_shift_right(tmp_bmp, tmp_bmp, UWB_MAS_PER_ZONE, UWB_NUM_MAS);
+ }
+
+ /* Store in format ready for transmission (le16). */
+ for (i = 0; i < num_fields; i++) {
+ drp_ie->allocs[i].zone_bm = cpu_to_le16(zones[i].zone_bm);
+ drp_ie->allocs[i].mas_bm = cpu_to_le16(zones[i].mas_bm);
+ }
+
+ drp_ie->hdr.length = sizeof(struct uwb_ie_drp) - sizeof(struct uwb_ie_hdr)
+ + num_fields * sizeof(struct uwb_drp_alloc);
+}
+
+/**
+ * uwb_drp_ie_update - update a reservation's DRP IE
+ * @rsv: the reservation
+ */
+int uwb_drp_ie_update(struct uwb_rsv *rsv)
+{
+ struct uwb_ie_drp *drp_ie;
+ struct uwb_rsv_move *mv;
+ int unsafe;
+
+ if (rsv->state == UWB_RSV_STATE_NONE) {
+ kfree(rsv->drp_ie);
+ rsv->drp_ie = NULL;
+ return 0;
+ }
+
+ unsafe = rsv->mas.unsafe ? 1 : 0;
+
+ if (rsv->drp_ie == NULL) {
+ rsv->drp_ie = uwb_drp_ie_alloc();
+ if (rsv->drp_ie == NULL)
+ return -ENOMEM;
+ }
+ drp_ie = rsv->drp_ie;
+
+ uwb_ie_drp_set_unsafe(drp_ie, unsafe);
+ uwb_ie_drp_set_tiebreaker(drp_ie, rsv->tiebreaker);
+ uwb_ie_drp_set_owner(drp_ie, uwb_rsv_is_owner(rsv));
+ uwb_ie_drp_set_status(drp_ie, uwb_rsv_status(rsv));
+ uwb_ie_drp_set_reason_code(drp_ie, uwb_rsv_reason_code(rsv));
+ uwb_ie_drp_set_stream_index(drp_ie, rsv->stream);
+ uwb_ie_drp_set_type(drp_ie, rsv->type);
+
+ if (uwb_rsv_is_owner(rsv)) {
+ switch (rsv->target.type) {
+ case UWB_RSV_TARGET_DEV:
+ drp_ie->dev_addr = rsv->target.dev->dev_addr;
+ break;
+ case UWB_RSV_TARGET_DEVADDR:
+ drp_ie->dev_addr = rsv->target.devaddr;
+ break;
+ }
+ } else
+ drp_ie->dev_addr = rsv->owner->dev_addr;
+
+ uwb_drp_ie_from_bm(drp_ie, &rsv->mas);
+
+ if (uwb_rsv_has_two_drp_ies(rsv)) {
+ mv = &rsv->mv;
+ if (mv->companion_drp_ie == NULL) {
+ mv->companion_drp_ie = uwb_drp_ie_alloc();
+ if (mv->companion_drp_ie == NULL)
+ return -ENOMEM;
+ }
+ drp_ie = mv->companion_drp_ie;
+
+ /* keep all the same configuration of the main drp_ie */
+ memcpy(drp_ie, rsv->drp_ie, sizeof(struct uwb_ie_drp));
+
+
+ /* FIXME: handle properly the unsafe bit */
+ uwb_ie_drp_set_unsafe(drp_ie, 1);
+ uwb_ie_drp_set_status(drp_ie, uwb_rsv_companion_status(rsv));
+ uwb_ie_drp_set_reason_code(drp_ie, uwb_rsv_companion_reason_code(rsv));
+
+ uwb_drp_ie_from_bm(drp_ie, &mv->companion_mas);
+ }
+
+ rsv->ie_valid = true;
+ return 0;
+}
+
+/*
+ * Set MAS bits from given MAS bitmap in a single zone of large bitmap.
+ *
+ * We are given a zone id and the MAS bitmap of bits that need to be set in
+ * this zone. Note that this zone may already have bits set and this only
+ * adds settings - we cannot simply assign the MAS bitmap contents to the
+ * zone contents. We iterate over the the bits (MAS) in the zone and set the
+ * bits that are set in the given MAS bitmap.
+ */
+static
+void uwb_drp_ie_single_zone_to_bm(struct uwb_mas_bm *bm, u8 zone, u16 mas_bm)
+{
+ int mas;
+ u16 mas_mask;
+
+ for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++) {
+ mas_mask = 1 << mas;
+ if (mas_bm & mas_mask)
+ set_bit(zone * UWB_NUM_ZONES + mas, bm->bm);
+ }
+}
+
+/**
+ * uwb_drp_ie_zones_to_bm - convert DRP allocation fields to a bitmap
+ * @mas: MAS bitmap that will be populated to correspond to the
+ * allocation fields in the DRP IE
+ * @drp_ie: the DRP IE that contains the allocation fields.
+ *
+ * The input format is an array of MAS allocation fields (16 bit Zone
+ * bitmap, 16 bit MAS bitmap) as described in [ECMA-368] section
+ * 16.8.6. The output is a full 256 bit MAS bitmap.
+ *
+ * We go over all the allocation fields, for each allocation field we
+ * know which zones are impacted. We iterate over all the zones
+ * impacted and call a function that will set the correct MAS bits in
+ * each zone.
+ */
+void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie)
+{
+ int numallocs = (drp_ie->hdr.length - 4) / 4;
+ const struct uwb_drp_alloc *alloc;
+ int cnt;
+ u16 zone_bm, mas_bm;
+ u8 zone;
+ u16 zone_mask;
+
+ bitmap_zero(bm->bm, UWB_NUM_MAS);
+
+ for (cnt = 0; cnt < numallocs; cnt++) {
+ alloc = &drp_ie->allocs[cnt];
+ zone_bm = le16_to_cpu(alloc->zone_bm);
+ mas_bm = le16_to_cpu(alloc->mas_bm);
+ for (zone = 0; zone < UWB_NUM_ZONES; zone++) {
+ zone_mask = 1 << zone;
+ if (zone_bm & zone_mask)
+ uwb_drp_ie_single_zone_to_bm(bm, zone, mas_bm);
+ }
+ }
+}
+
diff --git a/drivers/staging/uwb/drp.c b/drivers/staging/uwb/drp.c
new file mode 100644
index 000000000000..869987bede7b
--- /dev/null
+++ b/drivers/staging/uwb/drp.c
@@ -0,0 +1,842 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Dynamic Reservation Protocol handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "uwb-internal.h"
+
+
+/* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */
+enum uwb_drp_conflict_action {
+ /* Reservation is maintained, no action needed */
+ UWB_DRP_CONFLICT_MANTAIN = 0,
+
+ /* the device shall not transmit frames in conflicting MASs in
+ * the following superframe. If the device is the reservation
+ * target, it shall also set the Reason Code in its DRP IE to
+ * Conflict in its beacon in the following superframe.
+ */
+ UWB_DRP_CONFLICT_ACT1,
+
+ /* the device shall not set the Reservation Status bit to ONE
+ * and shall not transmit frames in conflicting MASs. If the
+ * device is the reservation target, it shall also set the
+ * Reason Code in its DRP IE to Conflict.
+ */
+ UWB_DRP_CONFLICT_ACT2,
+
+ /* the device shall not transmit frames in conflicting MASs in
+ * the following superframe. It shall remove the conflicting
+ * MASs from the reservation or set the Reservation Status to
+ * ZERO in its beacon in the following superframe. If the
+ * device is the reservation target, it shall also set the
+ * Reason Code in its DRP IE to Conflict.
+ */
+ UWB_DRP_CONFLICT_ACT3,
+};
+
+
+static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg,
+ struct uwb_rceb *reply, ssize_t reply_size)
+{
+ struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply;
+ unsigned long flags;
+
+ if (r != NULL) {
+ if (r->bResultCode != UWB_RC_RES_SUCCESS)
+ dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n",
+ uwb_rc_strerror(r->bResultCode), r->bResultCode);
+ } else
+ dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n");
+
+ spin_lock_irqsave(&rc->rsvs_lock, flags);
+ if (rc->set_drp_ie_pending > 1) {
+ rc->set_drp_ie_pending = 0;
+ uwb_rsv_queue_update(rc);
+ } else {
+ rc->set_drp_ie_pending = 0;
+ }
+ spin_unlock_irqrestore(&rc->rsvs_lock, flags);
+}
+
+/**
+ * Construct and send the SET DRP IE
+ *
+ * @rc: UWB Host controller
+ * @returns: >= 0 number of bytes still available in the beacon
+ * < 0 errno code on error.
+ *
+ * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the
+ * device to include in its beacon at the same time. We thus have to
+ * traverse all reservations and include the DRP IEs of all PENDING
+ * and NEGOTIATED reservations in a SET DRP command for transmission.
+ *
+ * A DRP Availability IE is appended.
+ *
+ * rc->rsvs_mutex is held
+ *
+ * FIXME We currently ignore the returned value indicating the remaining space
+ * in beacon. This could be used to deny reservation requests earlier if
+ * determined that they would cause the beacon space to be exceeded.
+ */
+int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
+{
+ int result;
+ struct uwb_rc_cmd_set_drp_ie *cmd;
+ struct uwb_rsv *rsv;
+ struct uwb_rsv_move *mv;
+ int num_bytes = 0;
+ u8 *IEDataptr;
+
+ result = -ENOMEM;
+ /* First traverse all reservations to determine memory needed. */
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (rsv->drp_ie != NULL) {
+ num_bytes += rsv->drp_ie->hdr.length + 2;
+ if (uwb_rsv_has_two_drp_ies(rsv) &&
+ (rsv->mv.companion_drp_ie != NULL)) {
+ mv = &rsv->mv;
+ num_bytes +=
+ mv->companion_drp_ie->hdr.length + 2;
+ }
+ }
+ }
+ num_bytes += sizeof(rc->drp_avail.ie);
+ cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL);
+ if (cmd == NULL)
+ goto error;
+ cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE);
+ cmd->wIELength = num_bytes;
+ IEDataptr = (u8 *)&cmd->IEData[0];
+
+ /* FIXME: DRV avail IE is not always needed */
+ /* put DRP avail IE first */
+ memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
+ IEDataptr += sizeof(struct uwb_ie_drp_avail);
+
+ /* Next traverse all reservations to place IEs in allocated memory. */
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (rsv->drp_ie != NULL) {
+ memcpy(IEDataptr, rsv->drp_ie,
+ rsv->drp_ie->hdr.length + 2);
+ IEDataptr += rsv->drp_ie->hdr.length + 2;
+
+ if (uwb_rsv_has_two_drp_ies(rsv) &&
+ (rsv->mv.companion_drp_ie != NULL)) {
+ mv = &rsv->mv;
+ memcpy(IEDataptr, mv->companion_drp_ie,
+ mv->companion_drp_ie->hdr.length + 2);
+ IEDataptr +=
+ mv->companion_drp_ie->hdr.length + 2;
+ }
+ }
+ }
+
+ result = uwb_rc_cmd_async(rc, "SET-DRP-IE",
+ &cmd->rccb, sizeof(*cmd) + num_bytes,
+ UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE,
+ uwb_rc_set_drp_cmd_done, NULL);
+
+ rc->set_drp_ie_pending = 1;
+
+ kfree(cmd);
+error:
+ return result;
+}
+
+/*
+ * Evaluate the action to perform using conflict resolution rules
+ *
+ * Return a uwb_drp_conflict_action.
+ */
+static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot,
+ struct uwb_rsv *rsv, int our_status)
+{
+ int our_tie_breaker = rsv->tiebreaker;
+ int our_type = rsv->type;
+ int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot;
+
+ int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie);
+ int ext_status = uwb_ie_drp_status(ext_drp_ie);
+ int ext_type = uwb_ie_drp_type(ext_drp_ie);
+
+
+ /* [ECMA-368 2nd Edition] 17.4.6 */
+ if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) {
+ return UWB_DRP_CONFLICT_MANTAIN;
+ }
+
+ /* [ECMA-368 2nd Edition] 17.4.6-1 */
+ if (our_type == UWB_DRP_TYPE_ALIEN_BP) {
+ return UWB_DRP_CONFLICT_MANTAIN;
+ }
+
+ /* [ECMA-368 2nd Edition] 17.4.6-2 */
+ if (ext_type == UWB_DRP_TYPE_ALIEN_BP) {
+ /* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */
+ return UWB_DRP_CONFLICT_ACT1;
+ }
+
+ /* [ECMA-368 2nd Edition] 17.4.6-3 */
+ if (our_status == 0 && ext_status == 1) {
+ return UWB_DRP_CONFLICT_ACT2;
+ }
+
+ /* [ECMA-368 2nd Edition] 17.4.6-4 */
+ if (our_status == 1 && ext_status == 0) {
+ return UWB_DRP_CONFLICT_MANTAIN;
+ }
+
+ /* [ECMA-368 2nd Edition] 17.4.6-5a */
+ if (our_tie_breaker == ext_tie_breaker &&
+ our_beacon_slot < ext_beacon_slot) {
+ return UWB_DRP_CONFLICT_MANTAIN;
+ }
+
+ /* [ECMA-368 2nd Edition] 17.4.6-5b */
+ if (our_tie_breaker != ext_tie_breaker &&
+ our_beacon_slot > ext_beacon_slot) {
+ return UWB_DRP_CONFLICT_MANTAIN;
+ }
+
+ if (our_status == 0) {
+ if (our_tie_breaker == ext_tie_breaker) {
+ /* [ECMA-368 2nd Edition] 17.4.6-6a */
+ if (our_beacon_slot > ext_beacon_slot) {
+ return UWB_DRP_CONFLICT_ACT2;
+ }
+ } else {
+ /* [ECMA-368 2nd Edition] 17.4.6-6b */
+ if (our_beacon_slot < ext_beacon_slot) {
+ return UWB_DRP_CONFLICT_ACT2;
+ }
+ }
+ } else {
+ if (our_tie_breaker == ext_tie_breaker) {
+ /* [ECMA-368 2nd Edition] 17.4.6-7a */
+ if (our_beacon_slot > ext_beacon_slot) {
+ return UWB_DRP_CONFLICT_ACT3;
+ }
+ } else {
+ /* [ECMA-368 2nd Edition] 17.4.6-7b */
+ if (our_beacon_slot < ext_beacon_slot) {
+ return UWB_DRP_CONFLICT_ACT3;
+ }
+ }
+ }
+ return UWB_DRP_CONFLICT_MANTAIN;
+}
+
+static void handle_conflict_normal(struct uwb_ie_drp *drp_ie,
+ int ext_beacon_slot,
+ struct uwb_rsv *rsv,
+ struct uwb_mas_bm *conflicting_mas)
+{
+ struct uwb_rc *rc = rsv->rc;
+ struct uwb_rsv_move *mv = &rsv->mv;
+ struct uwb_drp_backoff_win *bow = &rc->bow;
+ int action;
+
+ action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv));
+
+ if (uwb_rsv_is_owner(rsv)) {
+ switch(action) {
+ case UWB_DRP_CONFLICT_ACT2:
+ /* try move */
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED);
+ if (bow->can_reserve_extra_mases == false)
+ uwb_rsv_backoff_win_increment(rc);
+
+ break;
+ case UWB_DRP_CONFLICT_ACT3:
+ uwb_rsv_backoff_win_increment(rc);
+ /* drop some mases with reason modified */
+ /* put in the companion the mases to be dropped */
+ bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS);
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
+ default:
+ break;
+ }
+ } else {
+ switch(action) {
+ case UWB_DRP_CONFLICT_ACT2:
+ case UWB_DRP_CONFLICT_ACT3:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
+ default:
+ break;
+ }
+
+ }
+
+}
+
+static void handle_conflict_expanding(struct uwb_ie_drp *drp_ie, int ext_beacon_slot,
+ struct uwb_rsv *rsv, bool companion_only,
+ struct uwb_mas_bm *conflicting_mas)
+{
+ struct uwb_rc *rc = rsv->rc;
+ struct uwb_drp_backoff_win *bow = &rc->bow;
+ struct uwb_rsv_move *mv = &rsv->mv;
+ int action;
+
+ if (companion_only) {
+ /* status of companion is 0 at this point */
+ action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0);
+ if (uwb_rsv_is_owner(rsv)) {
+ switch(action) {
+ case UWB_DRP_CONFLICT_ACT2:
+ case UWB_DRP_CONFLICT_ACT3:
+ uwb_rsv_set_state(rsv,
+ UWB_RSV_STATE_O_ESTABLISHED);
+ rsv->needs_release_companion_mas = false;
+ if (bow->can_reserve_extra_mases == false)
+ uwb_rsv_backoff_win_increment(rc);
+ uwb_drp_avail_release(rsv->rc,
+ &rsv->mv.companion_mas);
+ }
+ } else { /* rsv is target */
+ switch(action) {
+ case UWB_DRP_CONFLICT_ACT2:
+ case UWB_DRP_CONFLICT_ACT3:
+ uwb_rsv_set_state(rsv,
+ UWB_RSV_STATE_T_EXPANDING_CONFLICT);
+ /* send_drp_avail_ie = true; */
+ }
+ }
+ } else { /* also base part of the reservation is conflicting */
+ if (uwb_rsv_is_owner(rsv)) {
+ uwb_rsv_backoff_win_increment(rc);
+ /* remove companion part */
+ uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
+
+ /* drop some mases with reason modified */
+
+ /* put in the companion the mases to be dropped */
+ bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm,
+ conflicting_mas->bm, UWB_NUM_MAS);
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
+ } else { /* it is a target rsv */
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
+ /* send_drp_avail_ie = true; */
+ }
+ }
+}
+
+static void uwb_drp_handle_conflict_rsv(struct uwb_rc *rc, struct uwb_rsv *rsv,
+ struct uwb_rc_evt_drp *drp_evt,
+ struct uwb_ie_drp *drp_ie,
+ struct uwb_mas_bm *conflicting_mas)
+{
+ struct uwb_rsv_move *mv;
+
+ /* check if the conflicting reservation has two drp_ies */
+ if (uwb_rsv_has_two_drp_ies(rsv)) {
+ mv = &rsv->mv;
+ if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
+ UWB_NUM_MAS)) {
+ handle_conflict_expanding(drp_ie,
+ drp_evt->beacon_slot_number,
+ rsv, false, conflicting_mas);
+ } else {
+ if (bitmap_intersects(mv->companion_mas.bm,
+ conflicting_mas->bm, UWB_NUM_MAS)) {
+ handle_conflict_expanding(
+ drp_ie, drp_evt->beacon_slot_number,
+ rsv, true, conflicting_mas);
+ }
+ }
+ } else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
+ UWB_NUM_MAS)) {
+ handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number,
+ rsv, conflicting_mas);
+ }
+}
+
+static void uwb_drp_handle_all_conflict_rsv(struct uwb_rc *rc,
+ struct uwb_rc_evt_drp *drp_evt,
+ struct uwb_ie_drp *drp_ie,
+ struct uwb_mas_bm *conflicting_mas)
+{
+ struct uwb_rsv *rsv;
+
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie,
+ conflicting_mas);
+ }
+}
+
+static void uwb_drp_process_target_accepted(struct uwb_rc *rc,
+ struct uwb_rsv *rsv, struct uwb_rc_evt_drp *drp_evt,
+ struct uwb_ie_drp *drp_ie, struct uwb_mas_bm *mas)
+{
+ struct uwb_rsv_move *mv = &rsv->mv;
+ int status;
+
+ status = uwb_ie_drp_status(drp_ie);
+
+ if (rsv->state == UWB_RSV_STATE_T_CONFLICT) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
+ return;
+ }
+
+ if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) {
+ /* drp_ie is companion */
+ if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
+ /* stroke companion */
+ uwb_rsv_set_state(rsv,
+ UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
+ }
+ } else {
+ if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
+ if (uwb_drp_avail_reserve_pending(rc, mas) == -EBUSY) {
+ /* FIXME: there is a conflict, find
+ * the conflicting reservations and
+ * take a sensible action. Consider
+ * that in drp_ie there is the
+ * "neighbour" */
+ uwb_drp_handle_all_conflict_rsv(rc, drp_evt,
+ drp_ie, mas);
+ } else {
+ /* accept the extra reservation */
+ bitmap_copy(mv->companion_mas.bm, mas->bm,
+ UWB_NUM_MAS);
+ uwb_rsv_set_state(rsv,
+ UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
+ }
+ } else {
+ if (status) {
+ uwb_rsv_set_state(rsv,
+ UWB_RSV_STATE_T_ACCEPTED);
+ }
+ }
+
+ }
+}
+
+/*
+ * Based on the DRP IE, transition a target reservation to a new
+ * state.
+ */
+static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
+ struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rsv_move *mv = &rsv->mv;
+ int status;
+ enum uwb_drp_reason reason_code;
+ struct uwb_mas_bm mas;
+
+ status = uwb_ie_drp_status(drp_ie);
+ reason_code = uwb_ie_drp_reason_code(drp_ie);
+ uwb_drp_ie_to_bm(&mas, drp_ie);
+
+ switch (reason_code) {
+ case UWB_DRP_REASON_ACCEPTED:
+ uwb_drp_process_target_accepted(rc, rsv, drp_evt, drp_ie, &mas);
+ break;
+
+ case UWB_DRP_REASON_MODIFIED:
+ /* check to see if we have already modified the reservation */
+ if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
+ break;
+ }
+
+ /* find if the owner wants to expand or reduce */
+ if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
+ /* owner is reducing */
+ bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm,
+ UWB_NUM_MAS);
+ uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
+ }
+
+ bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED);
+ break;
+ default:
+ dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+ reason_code, status);
+ }
+}
+
+static void uwb_drp_process_owner_accepted(struct uwb_rsv *rsv,
+ struct uwb_mas_bm *mas)
+{
+ struct uwb_rsv_move *mv = &rsv->mv;
+
+ switch (rsv->state) {
+ case UWB_RSV_STATE_O_PENDING:
+ case UWB_RSV_STATE_O_INITIATED:
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ break;
+ case UWB_RSV_STATE_O_MODIFIED:
+ if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ else
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
+ break;
+
+ case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */
+ if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ else
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+ break;
+ case UWB_RSV_STATE_O_MOVE_EXPANDING:
+ if (bitmap_equal(mas->bm, mv->companion_mas.bm, UWB_NUM_MAS)) {
+ /* Companion reservation accepted */
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+ } else {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
+ }
+ break;
+ case UWB_RSV_STATE_O_MOVE_COMBINING:
+ if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+ else
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+ break;
+ default:
+ break;
+ }
+}
+/*
+ * Based on the DRP IE, transition an owner reservation to a new
+ * state.
+ */
+static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
+ struct uwb_dev *src, struct uwb_ie_drp *drp_ie,
+ struct uwb_rc_evt_drp *drp_evt)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ int status;
+ enum uwb_drp_reason reason_code;
+ struct uwb_mas_bm mas;
+
+ status = uwb_ie_drp_status(drp_ie);
+ reason_code = uwb_ie_drp_reason_code(drp_ie);
+ uwb_drp_ie_to_bm(&mas, drp_ie);
+
+ if (status) {
+ switch (reason_code) {
+ case UWB_DRP_REASON_ACCEPTED:
+ uwb_drp_process_owner_accepted(rsv, &mas);
+ break;
+ default:
+ dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+ reason_code, status);
+ }
+ } else {
+ switch (reason_code) {
+ case UWB_DRP_REASON_PENDING:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING);
+ break;
+ case UWB_DRP_REASON_DENIED:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+ break;
+ case UWB_DRP_REASON_CONFLICT:
+ /* resolve the conflict */
+ bitmap_complement(mas.bm, src->last_availability_bm,
+ UWB_NUM_MAS);
+ uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas);
+ break;
+ default:
+ dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+ reason_code, status);
+ }
+ }
+}
+
+static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt)
+{
+ unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US;
+ mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us));
+}
+
+static void uwb_cnflt_update_work(struct work_struct *work)
+{
+ struct uwb_cnflt_alien *cnflt = container_of(work,
+ struct uwb_cnflt_alien,
+ cnflt_update_work);
+ struct uwb_cnflt_alien *c;
+ struct uwb_rc *rc = cnflt->rc;
+
+ unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ list_del(&cnflt->rc_node);
+
+ /* update rc global conflicting alien bitmap */
+ bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
+
+ list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) {
+ bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm,
+ c->mas.bm, UWB_NUM_MAS);
+ }
+
+ queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work,
+ usecs_to_jiffies(delay_us));
+
+ kfree(cnflt);
+ mutex_unlock(&rc->rsvs_mutex);
+}
+
+static void uwb_cnflt_timer(struct timer_list *t)
+{
+ struct uwb_cnflt_alien *cnflt = from_timer(cnflt, t, timer);
+
+ queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work);
+}
+
+/*
+ * We have received an DRP_IE of type Alien BP and we need to make
+ * sure we do not transmit in conflicting MASs.
+ */
+static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_mas_bm mas;
+ struct uwb_cnflt_alien *cnflt;
+ unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
+
+ uwb_drp_ie_to_bm(&mas, drp_ie);
+
+ list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
+ if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
+ /* Existing alien BP reservation conflicting
+ * bitmap, just reset the timer */
+ uwb_cnflt_alien_stroke_timer(cnflt);
+ return;
+ }
+ }
+
+ /* New alien BP reservation conflicting bitmap */
+
+ /* alloc and initialize new uwb_cnflt_alien */
+ cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL);
+ if (!cnflt) {
+ dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n");
+ return;
+ }
+
+ INIT_LIST_HEAD(&cnflt->rc_node);
+ timer_setup(&cnflt->timer, uwb_cnflt_timer, 0);
+
+ cnflt->rc = rc;
+ INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work);
+
+ bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS);
+
+ list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list);
+
+ /* update rc global conflicting alien bitmap */
+ bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS);
+
+ queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us));
+
+ /* start the timer */
+ uwb_cnflt_alien_stroke_timer(cnflt);
+}
+
+static void uwb_drp_process_not_involved(struct uwb_rc *rc,
+ struct uwb_rc_evt_drp *drp_evt,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_mas_bm mas;
+
+ uwb_drp_ie_to_bm(&mas, drp_ie);
+ uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas);
+}
+
+static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src,
+ struct uwb_rc_evt_drp *drp_evt,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_rsv *rsv;
+
+ rsv = uwb_rsv_find(rc, src, drp_ie);
+ if (!rsv) {
+ /*
+ * No reservation? It's either for a recently
+ * terminated reservation; or the DRP IE couldn't be
+ * processed (e.g., an invalid IE or out of memory).
+ */
+ return;
+ }
+
+ /*
+ * Do nothing with DRP IEs for reservations that have been
+ * terminated.
+ */
+ if (rsv->state == UWB_RSV_STATE_NONE) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+ return;
+ }
+
+ if (uwb_ie_drp_owner(drp_ie))
+ uwb_drp_process_target(rc, rsv, drp_ie, drp_evt);
+ else
+ uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt);
+
+}
+
+
+static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
+{
+ return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0;
+}
+
+/*
+ * Process a received DRP IE.
+ */
+static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
+ struct uwb_dev *src, struct uwb_ie_drp *drp_ie)
+{
+ if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP)
+ uwb_drp_handle_alien_drp(rc, drp_ie);
+ else if (uwb_drp_involves_us(rc, drp_ie))
+ uwb_drp_process_involved(rc, src, drp_evt, drp_ie);
+ else
+ uwb_drp_process_not_involved(rc, drp_evt, drp_ie);
+}
+
+/*
+ * Process a received DRP Availability IE
+ */
+static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src,
+ struct uwb_ie_drp_avail *drp_availability_ie)
+{
+ bitmap_copy(src->last_availability_bm,
+ drp_availability_ie->bmp, UWB_NUM_MAS);
+}
+
+/*
+ * Process all the DRP IEs (both DRP IEs and the DRP Availability IE)
+ * from a device.
+ */
+static
+void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
+ size_t ielen, struct uwb_dev *src_dev)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_ie_hdr *ie_hdr;
+ void *ptr;
+
+ ptr = drp_evt->ie_data;
+ for (;;) {
+ ie_hdr = uwb_ie_next(&ptr, &ielen);
+ if (!ie_hdr)
+ break;
+
+ switch (ie_hdr->element_id) {
+ case UWB_IE_DRP_AVAILABILITY:
+ uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr);
+ break;
+ case UWB_IE_DRP:
+ uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr);
+ break;
+ default:
+ dev_warn(dev, "unexpected IE in DRP notification\n");
+ break;
+ }
+ }
+
+ if (ielen > 0)
+ dev_warn(dev, "%d octets remaining in DRP notification\n",
+ (int)ielen);
+}
+
+/**
+ * uwbd_evt_handle_rc_drp - handle a DRP_IE event
+ * @evt: the DRP_IE event from the radio controller
+ *
+ * This processes DRP notifications from the radio controller, either
+ * initiating a new reservation or transitioning an existing
+ * reservation into a different state.
+ *
+ * DRP notifications can occur for three different reasons:
+ *
+ * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as
+ * the target or source have been received.
+ *
+ * These DRP IEs could be new or for an existing reservation.
+ *
+ * If the DRP IE for an existing reservation ceases to be to
+ * received for at least mMaxLostBeacons, the reservation should be
+ * considered to be terminated. Note that the TERMINATE reason (see
+ * below) may not always be signalled (e.g., the remote device has
+ * two or more reservations established with the RC).
+ *
+ * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon
+ * group conflict with the RC's reservations.
+ *
+ * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received
+ * from a device (i.e., it's terminated all reservations).
+ *
+ * Only the software state of the reservations is changed; the setting
+ * of the radio controller's DRP IEs is done after all the events in
+ * an event buffer are processed. This saves waiting multiple times
+ * for the SET_DRP_IE command to complete.
+ */
+int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
+{
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc *rc = evt->rc;
+ struct uwb_rc_evt_drp *drp_evt;
+ size_t ielength, bytes_left;
+ struct uwb_dev_addr src_addr;
+ struct uwb_dev *src_dev;
+
+ /* Is there enough data to decode the event (and any IEs in
+ its payload)? */
+ if (evt->notif.size < sizeof(*drp_evt)) {
+ dev_err(dev, "DRP event: Not enough data to decode event "
+ "[%zu bytes left, %zu needed]\n",
+ evt->notif.size, sizeof(*drp_evt));
+ return 0;
+ }
+ bytes_left = evt->notif.size - sizeof(*drp_evt);
+ drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb);
+ ielength = le16_to_cpu(drp_evt->ie_length);
+ if (bytes_left != ielength) {
+ dev_err(dev, "DRP event: Not enough data in payload [%zu"
+ "bytes left, %zu declared in the event]\n",
+ bytes_left, ielength);
+ return 0;
+ }
+
+ memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr));
+ src_dev = uwb_dev_get_by_devaddr(rc, &src_addr);
+ if (!src_dev) {
+ /*
+ * A DRP notification from an unrecognized device.
+ *
+ * This is probably from a WUSB device that doesn't
+ * have an EUI-48 and therefore doesn't show up in the
+ * UWB device database. It's safe to simply ignore
+ * these.
+ */
+ return 0;
+ }
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ /* We do not distinguish from the reason */
+ uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
+
+ mutex_unlock(&rc->rsvs_mutex);
+
+ uwb_dev_put(src_dev);
+ return 0;
+}
diff --git a/drivers/staging/uwb/est.c b/drivers/staging/uwb/est.c
new file mode 100644
index 000000000000..d4141ffdd775
--- /dev/null
+++ b/drivers/staging/uwb/est.c
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band Radio Control
+ * Event Size Tables management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ *
+ * Infrastructure, code and data tables for guessing the size of
+ * events received on the notification endpoints of UWB radio
+ * controllers.
+ *
+ * You define a table of events and for each, its size and how to get
+ * the extra size.
+ *
+ * ENTRY POINTS:
+ *
+ * uwb_est_{init/destroy}(): To initialize/release the EST subsystem.
+ *
+ * uwb_est_[u]register(): To un/register event size tables
+ * uwb_est_grow()
+ *
+ * uwb_est_find_size(): Get the size of an event
+ * uwb_est_get_size()
+ */
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "uwb-internal.h"
+
+struct uwb_est {
+ u16 type_event_high;
+ u16 vendor, product;
+ u8 entries;
+ const struct uwb_est_entry *entry;
+};
+
+static struct uwb_est *uwb_est;
+static u8 uwb_est_size;
+static u8 uwb_est_used;
+static DEFINE_RWLOCK(uwb_est_lock);
+
+/**
+ * WUSB Standard Event Size Table, HWA-RC interface
+ *
+ * Sizes for events and notifications type 0 (general), high nibble 0.
+ */
+static
+struct uwb_est_entry uwb_est_00_00xx[] = {
+ [UWB_RC_EVT_IE_RCV] = {
+ .size = sizeof(struct uwb_rc_evt_ie_rcv),
+ .offset = 1 + offsetof(struct uwb_rc_evt_ie_rcv, wIELength),
+ },
+ [UWB_RC_EVT_BEACON] = {
+ .size = sizeof(struct uwb_rc_evt_beacon),
+ .offset = 1 + offsetof(struct uwb_rc_evt_beacon, wBeaconInfoLength),
+ },
+ [UWB_RC_EVT_BEACON_SIZE] = {
+ .size = sizeof(struct uwb_rc_evt_beacon_size),
+ },
+ [UWB_RC_EVT_BPOIE_CHANGE] = {
+ .size = sizeof(struct uwb_rc_evt_bpoie_change),
+ .offset = 1 + offsetof(struct uwb_rc_evt_bpoie_change,
+ wBPOIELength),
+ },
+ [UWB_RC_EVT_BP_SLOT_CHANGE] = {
+ .size = sizeof(struct uwb_rc_evt_bp_slot_change),
+ },
+ [UWB_RC_EVT_BP_SWITCH_IE_RCV] = {
+ .size = sizeof(struct uwb_rc_evt_bp_switch_ie_rcv),
+ .offset = 1 + offsetof(struct uwb_rc_evt_bp_switch_ie_rcv, wIELength),
+ },
+ [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
+ .size = sizeof(struct uwb_rc_evt_dev_addr_conflict),
+ },
+ [UWB_RC_EVT_DRP_AVAIL] = {
+ .size = sizeof(struct uwb_rc_evt_drp_avail)
+ },
+ [UWB_RC_EVT_DRP] = {
+ .size = sizeof(struct uwb_rc_evt_drp),
+ .offset = 1 + offsetof(struct uwb_rc_evt_drp, ie_length),
+ },
+ [UWB_RC_EVT_BP_SWITCH_STATUS] = {
+ .size = sizeof(struct uwb_rc_evt_bp_switch_status),
+ },
+ [UWB_RC_EVT_CMD_FRAME_RCV] = {
+ .size = sizeof(struct uwb_rc_evt_cmd_frame_rcv),
+ .offset = 1 + offsetof(struct uwb_rc_evt_cmd_frame_rcv, dataLength),
+ },
+ [UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV] = {
+ .size = sizeof(struct uwb_rc_evt_channel_change_ie_rcv),
+ .offset = 1 + offsetof(struct uwb_rc_evt_channel_change_ie_rcv, wIELength),
+ },
+ [UWB_RC_CMD_CHANNEL_CHANGE] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_DEV_ADDR_MGMT] = {
+ .size = sizeof(struct uwb_rc_evt_dev_addr_mgmt) },
+ [UWB_RC_CMD_GET_IE] = {
+ .size = sizeof(struct uwb_rc_evt_get_ie),
+ .offset = 1 + offsetof(struct uwb_rc_evt_get_ie, wIELength),
+ },
+ [UWB_RC_CMD_RESET] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SCAN] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SET_BEACON_FILTER] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SET_DRP_IE] = {
+ .size = sizeof(struct uwb_rc_evt_set_drp_ie),
+ },
+ [UWB_RC_CMD_SET_IE] = {
+ .size = sizeof(struct uwb_rc_evt_set_ie),
+ },
+ [UWB_RC_CMD_SET_NOTIFICATION_FILTER] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SET_TX_POWER] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SLEEP] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_START_BEACON] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_STOP_BEACON] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_BP_MERGE] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SEND_COMMAND_FRAME] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SET_ASIE_NOTIF] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+};
+
+static
+struct uwb_est_entry uwb_est_01_00xx[] = {
+ [UWB_RC_DAA_ENERGY_DETECTED] = {
+ .size = sizeof(struct uwb_rc_evt_daa_energy_detected),
+ },
+ [UWB_RC_SET_DAA_ENERGY_MASK] = {
+ .size = sizeof(struct uwb_rc_evt_set_daa_energy_mask),
+ },
+ [UWB_RC_SET_NOTIFICATION_FILTER_EX] = {
+ .size = sizeof(struct uwb_rc_evt_set_notification_filter_ex),
+ },
+};
+
+/**
+ * Initialize the EST subsystem
+ *
+ * Register the standard tables also.
+ *
+ * FIXME: tag init
+ */
+int uwb_est_create(void)
+{
+ int result;
+
+ uwb_est_size = 2;
+ uwb_est_used = 0;
+ uwb_est = kcalloc(uwb_est_size, sizeof(uwb_est[0]), GFP_KERNEL);
+ if (uwb_est == NULL)
+ return -ENOMEM;
+
+ result = uwb_est_register(UWB_RC_CET_GENERAL, 0, 0xffff, 0xffff,
+ uwb_est_00_00xx, ARRAY_SIZE(uwb_est_00_00xx));
+ if (result < 0)
+ goto out;
+ result = uwb_est_register(UWB_RC_CET_EX_TYPE_1, 0, 0xffff, 0xffff,
+ uwb_est_01_00xx, ARRAY_SIZE(uwb_est_01_00xx));
+out:
+ return result;
+}
+
+
+/** Clean it up */
+void uwb_est_destroy(void)
+{
+ kfree(uwb_est);
+ uwb_est = NULL;
+ uwb_est_size = uwb_est_used = 0;
+}
+
+
+/**
+ * Double the capacity of the EST table
+ *
+ * @returns 0 if ok, < 0 errno no error.
+ */
+static
+int uwb_est_grow(void)
+{
+ size_t actual_size = uwb_est_size * sizeof(uwb_est[0]);
+ void *new = kmalloc_array(2, actual_size, GFP_ATOMIC);
+ if (new == NULL)
+ return -ENOMEM;
+ memcpy(new, uwb_est, actual_size);
+ memset(new + actual_size, 0, actual_size);
+ kfree(uwb_est);
+ uwb_est = new;
+ uwb_est_size *= 2;
+ return 0;
+}
+
+
+/**
+ * Register an event size table
+ *
+ * Makes room for it if the table is full, and then inserts it in the
+ * right position (entries are sorted by type, event_high, vendor and
+ * then product).
+ *
+ * @vendor: vendor code for matching against the device (0x0000 and
+ * 0xffff mean any); use 0x0000 to force all to match without
+ * checking possible vendor specific ones, 0xfffff to match
+ * after checking vendor specific ones.
+ *
+ * @product: product code from that vendor; same matching rules, use
+ * 0x0000 for not allowing vendor specific matches, 0xffff
+ * for allowing.
+ *
+ * This arragement just makes the tables sort differenty. Because the
+ * table is sorted by growing type-event_high-vendor-product, a zero
+ * vendor will match before than a 0x456a vendor, that will match
+ * before a 0xfffff vendor.
+ *
+ * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
+ */
+/* FIXME: add bus type to vendor/product code */
+int uwb_est_register(u8 type, u8 event_high, u16 vendor, u16 product,
+ const struct uwb_est_entry *entry, size_t entries)
+{
+ unsigned long flags;
+ unsigned itr;
+ int result = 0;
+
+ write_lock_irqsave(&uwb_est_lock, flags);
+ if (uwb_est_used == uwb_est_size) {
+ result = uwb_est_grow();
+ if (result < 0)
+ goto out;
+ }
+ /* Find the right spot to insert it in */
+ for (itr = 0; itr < uwb_est_used; itr++)
+ if (uwb_est[itr].type_event_high < type
+ && uwb_est[itr].vendor < vendor
+ && uwb_est[itr].product < product)
+ break;
+
+ /* Shift others to make room for the new one? */
+ if (itr < uwb_est_used)
+ memmove(&uwb_est[itr+1], &uwb_est[itr], uwb_est_used - itr);
+ uwb_est[itr].type_event_high = type << 8 | event_high;
+ uwb_est[itr].vendor = vendor;
+ uwb_est[itr].product = product;
+ uwb_est[itr].entry = entry;
+ uwb_est[itr].entries = entries;
+ uwb_est_used++;
+out:
+ write_unlock_irqrestore(&uwb_est_lock, flags);
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_est_register);
+
+
+/**
+ * Unregister an event size table
+ *
+ * This just removes the specified entry and moves the ones after it
+ * to fill in the gap. This is needed to keep the list sorted; no
+ * reallocation is done to reduce the size of the table.
+ *
+ * We unregister by all the data we used to register instead of by
+ * pointer to the @entry array because we might have used the same
+ * table for a bunch of IDs (for example).
+ *
+ * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
+ */
+int uwb_est_unregister(u8 type, u8 event_high, u16 vendor, u16 product,
+ const struct uwb_est_entry *entry, size_t entries)
+{
+ unsigned long flags;
+ unsigned itr;
+ struct uwb_est est_cmp = {
+ .type_event_high = type << 8 | event_high,
+ .vendor = vendor,
+ .product = product,
+ .entry = entry,
+ .entries = entries
+ };
+ write_lock_irqsave(&uwb_est_lock, flags);
+ for (itr = 0; itr < uwb_est_used; itr++)
+ if (!memcmp(&uwb_est[itr], &est_cmp, sizeof(est_cmp)))
+ goto found;
+ write_unlock_irqrestore(&uwb_est_lock, flags);
+ return -ENOENT;
+
+found:
+ if (itr < uwb_est_used - 1) /* Not last one? move ones above */
+ memmove(&uwb_est[itr], &uwb_est[itr+1], uwb_est_used - itr - 1);
+ uwb_est_used--;
+ write_unlock_irqrestore(&uwb_est_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_est_unregister);
+
+
+/**
+ * Get the size of an event from a table
+ *
+ * @rceb: pointer to the buffer with the event
+ * @rceb_size: size of the area pointed to by @rceb in bytes.
+ * @returns: > 0 Size of the event
+ * -ENOSPC An area big enough was not provided to look
+ * ahead into the event's guts and guess the size.
+ * -EINVAL Unknown event code (wEvent).
+ *
+ * This will look at the received RCEB and guess what is the total
+ * size. For variable sized events, it will look further ahead into
+ * their length field to see how much data should be read.
+ *
+ * Note this size is *not* final--the neh (Notification/Event Handle)
+ * might specificy an extra size to add.
+ */
+static
+ssize_t uwb_est_get_size(struct uwb_rc *uwb_rc, struct uwb_est *est,
+ u8 event_low, const struct uwb_rceb *rceb,
+ size_t rceb_size)
+{
+ unsigned offset;
+ ssize_t size;
+ struct device *dev = &uwb_rc->uwb_dev.dev;
+ const struct uwb_est_entry *entry;
+
+ size = -ENOENT;
+ if (event_low >= est->entries) { /* in range? */
+ dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u out of range\n",
+ est, est->type_event_high, est->vendor, est->product,
+ est->entries, event_low);
+ goto out;
+ }
+ size = -ENOENT;
+ entry = &est->entry[event_low];
+ if (entry->size == 0 && entry->offset == 0) { /* unknown? */
+ dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u unknown\n",
+ est, est->type_event_high, est->vendor, est->product,
+ est->entries, event_low);
+ goto out;
+ }
+ offset = entry->offset; /* extra fries with that? */
+ if (offset == 0)
+ size = entry->size;
+ else {
+ /* Ops, got an extra size field at 'offset'--read it */
+ const void *ptr = rceb;
+ size_t type_size = 0;
+ offset--;
+ size = -ENOSPC; /* enough data for more? */
+ switch (entry->type) {
+ case UWB_EST_16: type_size = sizeof(__le16); break;
+ case UWB_EST_8: type_size = sizeof(u8); break;
+ default: BUG();
+ }
+ if (offset + type_size > rceb_size) {
+ dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: "
+ "not enough data to read extra size\n",
+ est, est->type_event_high, est->vendor,
+ est->product, est->entries);
+ goto out;
+ }
+ size = entry->size;
+ ptr += offset;
+ switch (entry->type) {
+ case UWB_EST_16: size += le16_to_cpu(*(__le16 *)ptr); break;
+ case UWB_EST_8: size += *(u8 *)ptr; break;
+ default: BUG();
+ }
+ }
+out:
+ return size;
+}
+
+
+/**
+ * Guesses the size of a WA event
+ *
+ * @rceb: pointer to the buffer with the event
+ * @rceb_size: size of the area pointed to by @rceb in bytes.
+ * @returns: > 0 Size of the event
+ * -ENOSPC An area big enough was not provided to look
+ * ahead into the event's guts and guess the size.
+ * -EINVAL Unknown event code (wEvent).
+ *
+ * This will look at the received RCEB and guess what is the total
+ * size by checking all the tables registered with
+ * uwb_est_register(). For variable sized events, it will look further
+ * ahead into their length field to see how much data should be read.
+ *
+ * Note this size is *not* final--the neh (Notification/Event Handle)
+ * might specificy an extra size to add or replace.
+ */
+ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
+ size_t rceb_size)
+{
+ /* FIXME: add vendor/product data */
+ ssize_t size;
+ struct device *dev = &rc->uwb_dev.dev;
+ unsigned long flags;
+ unsigned itr;
+ u16 type_event_high, event;
+
+ read_lock_irqsave(&uwb_est_lock, flags);
+ size = -ENOSPC;
+ if (rceb_size < sizeof(*rceb))
+ goto out;
+ event = le16_to_cpu(rceb->wEvent);
+ type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8;
+ for (itr = 0; itr < uwb_est_used; itr++) {
+ if (uwb_est[itr].type_event_high != type_event_high)
+ continue;
+ size = uwb_est_get_size(rc, &uwb_est[itr],
+ event & 0x00ff, rceb, rceb_size);
+ /* try more tables that might handle the same type */
+ if (size != -ENOENT)
+ goto out;
+ }
+ dev_dbg(dev,
+ "event 0x%02x/%04x/%02x: no handlers available; RCEB %4ph\n",
+ (unsigned) rceb->bEventType,
+ (unsigned) le16_to_cpu(rceb->wEvent),
+ (unsigned) rceb->bEventContext,
+ rceb);
+ size = -ENOENT;
+out:
+ read_unlock_irqrestore(&uwb_est_lock, flags);
+ return size;
+}
+EXPORT_SYMBOL_GPL(uwb_est_find_size);
diff --git a/drivers/staging/uwb/hwa-rc.c b/drivers/staging/uwb/hwa-rc.c
new file mode 100644
index 000000000000..b6effad749d7
--- /dev/null
+++ b/drivers/staging/uwb/hwa-rc.c
@@ -0,0 +1,929 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * WUSB Host Wire Adapter: Radio Control Interface (WUSB[8.6])
+ * Radio Control command/event transport
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Initialize the Radio Control interface Driver.
+ *
+ * For each device probed, creates an 'struct hwarc' which contains
+ * just the representation of the UWB Radio Controller, and the logic
+ * for reading notifications and passing them to the UWB Core.
+ *
+ * So we initialize all of those, register the UWB Radio Controller
+ * and setup the notification/event handle to pipe the notifications
+ * to the UWB management Daemon.
+ *
+ * Command and event filtering.
+ *
+ * This is the driver for the Radio Control Interface described in WUSB
+ * 1.0. The core UWB module assumes that all drivers are compliant to the
+ * WHCI 0.95 specification. We thus create a filter that parses all
+ * incoming messages from the (WUSB 1.0) device and manipulate them to
+ * conform to the WHCI 0.95 specification. Similarly, outgoing messages
+ * are parsed and manipulated to conform to the WUSB 1.0 compliant messages
+ * that the device expects. Only a few messages are affected:
+ * Affected events:
+ * UWB_RC_EVT_BEACON
+ * UWB_RC_EVT_BP_SLOT_CHANGE
+ * UWB_RC_EVT_DRP_AVAIL
+ * UWB_RC_EVT_DRP
+ * Affected commands:
+ * UWB_RC_CMD_SCAN
+ * UWB_RC_CMD_SET_DRP_IE
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "../wusbcore/include/wusb.h"
+#include "../wusbcore/include/wusb-wa.h"
+#include "uwb.h"
+
+#include "uwb-internal.h"
+
+/* The device uses commands and events from the WHCI specification, although
+ * reporting itself as WUSB compliant. */
+#define WUSB_QUIRK_WHCI_CMD_EVT 0x01
+
+/**
+ * Descriptor for an instance of the UWB Radio Control Driver that
+ * attaches to the RCI interface of the Host Wired Adapter.
+ *
+ * Unless there is a lock specific to the 'data members', all access
+ * is protected by uwb_rc->mutex.
+ *
+ * The NEEP (Notification/Event EndPoint) URB (@neep_urb) writes to
+ * @rd_buffer. Note there is no locking because it is perfectly (heh!)
+ * serialized--probe() submits an URB, callback is called, processes
+ * the data (synchronously), submits another URB, and so on. There is
+ * no concurrent access to the buffer.
+ */
+struct hwarc {
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+ struct uwb_rc *uwb_rc; /* UWB host controller */
+ struct urb *neep_urb; /* Notification endpoint handling */
+ struct edc neep_edc;
+ void *rd_buffer; /* NEEP read buffer */
+};
+
+
+/* Beacon received notification (WUSB 1.0 [8.6.3.2]) */
+struct uwb_rc_evt_beacon_WUSB_0100 {
+ struct uwb_rceb rceb;
+ u8 bChannelNumber;
+ __le16 wBPSTOffset;
+ u8 bLQI;
+ u8 bRSSI;
+ __le16 wBeaconInfoLength;
+ u8 BeaconInfo[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 BEACON RCV notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ *
+ * The WHCI 0.95 spec has a "Beacon Type" field. This value is unknown at
+ * the time we receive the beacon from WUSB so we just set it to
+ * UWB_RC_BEACON_TYPE_NEIGHBOR as a default.
+ * The solution below allocates memory upon receipt of every beacon from a
+ * WUSB device. This will deteriorate performance. What is the right way to
+ * do this?
+ */
+static
+int hwarc_filter_evt_beacon_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rceb **header,
+ const size_t buf_size,
+ size_t *new_size)
+{
+ struct uwb_rc_evt_beacon_WUSB_0100 *be;
+ struct uwb_rc_evt_beacon *newbe;
+ size_t bytes_left, ielength;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ be = container_of(*header, struct uwb_rc_evt_beacon_WUSB_0100, rceb);
+ bytes_left = buf_size;
+ if (bytes_left < sizeof(*be)) {
+ dev_err(dev, "Beacon Received Notification: Not enough data "
+ "to decode for filtering (%zu vs %zu bytes needed)\n",
+ bytes_left, sizeof(*be));
+ return -EINVAL;
+ }
+ bytes_left -= sizeof(*be);
+ ielength = le16_to_cpu(be->wBeaconInfoLength);
+ if (bytes_left < ielength) {
+ dev_err(dev, "Beacon Received Notification: Not enough data "
+ "to decode IEs (%zu vs %zu bytes needed)\n",
+ bytes_left, ielength);
+ return -EINVAL;
+ }
+ newbe = kzalloc(sizeof(*newbe) + ielength, GFP_ATOMIC);
+ if (newbe == NULL)
+ return -ENOMEM;
+ newbe->rceb = be->rceb;
+ newbe->bChannelNumber = be->bChannelNumber;
+ newbe->bBeaconType = UWB_RC_BEACON_TYPE_NEIGHBOR;
+ newbe->wBPSTOffset = be->wBPSTOffset;
+ newbe->bLQI = be->bLQI;
+ newbe->bRSSI = be->bRSSI;
+ newbe->wBeaconInfoLength = be->wBeaconInfoLength;
+ memcpy(newbe->BeaconInfo, be->BeaconInfo, ielength);
+ *header = &newbe->rceb;
+ *new_size = sizeof(*newbe) + ielength;
+ return 1; /* calling function will free memory */
+}
+
+
+/* DRP Availability change notification (WUSB 1.0 [8.6.3.8]) */
+struct uwb_rc_evt_drp_avail_WUSB_0100 {
+ struct uwb_rceb rceb;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 DRP AVAILABILITY CHANGE notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ */
+static
+int hwarc_filter_evt_drp_avail_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rceb **header,
+ const size_t buf_size,
+ size_t *new_size)
+{
+ struct uwb_rc_evt_drp_avail_WUSB_0100 *da;
+ struct uwb_rc_evt_drp_avail *newda;
+ struct uwb_ie_hdr *ie_hdr;
+ size_t bytes_left, ielength;
+ struct device *dev = &rc->uwb_dev.dev;
+
+
+ da = container_of(*header, struct uwb_rc_evt_drp_avail_WUSB_0100, rceb);
+ bytes_left = buf_size;
+ if (bytes_left < sizeof(*da)) {
+ dev_err(dev, "Not enough data to decode DRP Avail "
+ "Notification for filtering. Expected %zu, "
+ "received %zu.\n", (size_t)sizeof(*da), bytes_left);
+ return -EINVAL;
+ }
+ bytes_left -= sizeof(*da);
+ ielength = le16_to_cpu(da->wIELength);
+ if (bytes_left < ielength) {
+ dev_err(dev, "DRP Avail Notification filter: IE length "
+ "[%zu bytes] does not match actual length "
+ "[%zu bytes].\n", ielength, bytes_left);
+ return -EINVAL;
+ }
+ if (ielength < sizeof(*ie_hdr)) {
+ dev_err(dev, "DRP Avail Notification filter: Not enough "
+ "data to decode IE [%zu bytes, %zu needed]\n",
+ ielength, sizeof(*ie_hdr));
+ return -EINVAL;
+ }
+ ie_hdr = (void *) da->IEData;
+ if (ie_hdr->length > 32) {
+ dev_err(dev, "DRP Availability Change event has unexpected "
+ "length for filtering. Expected < 32 bytes, "
+ "got %zu bytes.\n", (size_t)ie_hdr->length);
+ return -EINVAL;
+ }
+ newda = kzalloc(sizeof(*newda), GFP_ATOMIC);
+ if (newda == NULL)
+ return -ENOMEM;
+ newda->rceb = da->rceb;
+ memcpy(newda->bmp, (u8 *) ie_hdr + sizeof(*ie_hdr), ie_hdr->length);
+ *header = &newda->rceb;
+ *new_size = sizeof(*newda);
+ return 1; /* calling function will free memory */
+}
+
+
+/* DRP notification (WUSB 1.0 [8.6.3.9]) */
+struct uwb_rc_evt_drp_WUSB_0100 {
+ struct uwb_rceb rceb;
+ struct uwb_dev_addr wSrcAddr;
+ u8 bExplicit;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 DRP Notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ *
+ * It is hard to manage DRP reservations without having a Reason code.
+ * Unfortunately there is none in the WUSB spec. We just set the default to
+ * DRP IE RECEIVED.
+ * We do not currently use the bBeaconSlotNumber value, so we set this to
+ * zero for now.
+ */
+static
+int hwarc_filter_evt_drp_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rceb **header,
+ const size_t buf_size,
+ size_t *new_size)
+{
+ struct uwb_rc_evt_drp_WUSB_0100 *drpev;
+ struct uwb_rc_evt_drp *newdrpev;
+ size_t bytes_left, ielength;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ drpev = container_of(*header, struct uwb_rc_evt_drp_WUSB_0100, rceb);
+ bytes_left = buf_size;
+ if (bytes_left < sizeof(*drpev)) {
+ dev_err(dev, "Not enough data to decode DRP Notification "
+ "for filtering. Expected %zu, received %zu.\n",
+ (size_t)sizeof(*drpev), bytes_left);
+ return -EINVAL;
+ }
+ ielength = le16_to_cpu(drpev->wIELength);
+ bytes_left -= sizeof(*drpev);
+ if (bytes_left < ielength) {
+ dev_err(dev, "DRP Notification filter: header length [%zu "
+ "bytes] does not match actual length [%zu "
+ "bytes].\n", ielength, bytes_left);
+ return -EINVAL;
+ }
+ newdrpev = kzalloc(sizeof(*newdrpev) + ielength, GFP_ATOMIC);
+ if (newdrpev == NULL)
+ return -ENOMEM;
+ newdrpev->rceb = drpev->rceb;
+ newdrpev->src_addr = drpev->wSrcAddr;
+ newdrpev->reason = UWB_DRP_NOTIF_DRP_IE_RCVD;
+ newdrpev->beacon_slot_number = 0;
+ newdrpev->ie_length = drpev->wIELength;
+ memcpy(newdrpev->ie_data, drpev->IEData, ielength);
+ *header = &newdrpev->rceb;
+ *new_size = sizeof(*newdrpev) + ielength;
+ return 1; /* calling function will free memory */
+}
+
+
+/* Scan Command (WUSB 1.0 [8.6.2.5]) */
+struct uwb_rc_cmd_scan_WUSB_0100 {
+ struct uwb_rccb rccb;
+ u8 bChannelNumber;
+ u8 bScanState;
+} __attribute__((packed));
+
+/**
+ * Filter WHCI 0.95 SCAN command to be WUSB 1.0 SCAN command
+ *
+ * @header: command sent to device (compliant to WHCI 0.95)
+ * @size: size of command sent to device
+ *
+ * We only reduce the size by two bytes because the WUSB 1.0 scan command
+ * does not have the last field (wStarttime). Also, make sure we don't send
+ * the device an unexpected scan type.
+ */
+static
+int hwarc_filter_cmd_scan_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rccb **header,
+ size_t *size)
+{
+ struct uwb_rc_cmd_scan *sc;
+
+ sc = container_of(*header, struct uwb_rc_cmd_scan, rccb);
+
+ if (sc->bScanState == UWB_SCAN_ONLY_STARTTIME)
+ sc->bScanState = UWB_SCAN_ONLY;
+ /* Don't send the last two bytes. */
+ *size -= 2;
+ return 0;
+}
+
+
+/* SET DRP IE command (WUSB 1.0 [8.6.2.7]) */
+struct uwb_rc_cmd_set_drp_ie_WUSB_0100 {
+ struct uwb_rccb rccb;
+ u8 bExplicit;
+ __le16 wIELength;
+ struct uwb_ie_drp IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WHCI 0.95 SET DRP IE command to be WUSB 1.0 SET DRP IE command
+ *
+ * @header: command sent to device (compliant to WHCI 0.95)
+ * @size: size of command sent to device
+ *
+ * WUSB has an extra bExplicit field - we assume always explicit
+ * negotiation so this field is set. The command expected by the device is
+ * thus larger than the one prepared by the driver so we need to
+ * reallocate memory to accommodate this.
+ * We trust the driver to send us the correct data so no checking is done
+ * on incoming data - evn though it is variable length.
+ */
+static
+int hwarc_filter_cmd_set_drp_ie_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rccb **header,
+ size_t *size)
+{
+ struct uwb_rc_cmd_set_drp_ie *orgcmd;
+ struct uwb_rc_cmd_set_drp_ie_WUSB_0100 *cmd;
+ size_t ielength;
+
+ orgcmd = container_of(*header, struct uwb_rc_cmd_set_drp_ie, rccb);
+ ielength = le16_to_cpu(orgcmd->wIELength);
+ cmd = kzalloc(sizeof(*cmd) + ielength, GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+ cmd->rccb = orgcmd->rccb;
+ cmd->bExplicit = 0;
+ cmd->wIELength = orgcmd->wIELength;
+ memcpy(cmd->IEData, orgcmd->IEData, ielength);
+ *header = &cmd->rccb;
+ *size = sizeof(*cmd) + ielength;
+ return 1; /* calling function will free memory */
+}
+
+
+/**
+ * Filter data from WHCI driver to WUSB device
+ *
+ * @header: WHCI 0.95 compliant command from driver
+ * @size: length of command
+ *
+ * The routine managing commands to the device (uwb_rc_cmd()) will call the
+ * filtering function pointer (if it exists) before it passes any data to
+ * the device. At this time the command has been formatted according to
+ * WHCI 0.95 and is ready to be sent to the device.
+ *
+ * The filter function will be provided with the current command and its
+ * length. The function will manipulate the command if necessary and
+ * potentially reallocate memory for a command that needed more memory that
+ * the given command. If new memory was created the function will return 1
+ * to indicate to the calling function that the memory need to be freed
+ * when not needed any more. The size will contain the new length of the
+ * command.
+ * If memory has not been allocated we rely on the original mechanisms to
+ * free the memory of the command - even when we reduce the value of size.
+ */
+static
+int hwarc_filter_cmd_WUSB_0100(struct uwb_rc *rc, struct uwb_rccb **header,
+ size_t *size)
+{
+ int result;
+ struct uwb_rccb *rccb = *header;
+ int cmd = le16_to_cpu(rccb->wCommand);
+ switch (cmd) {
+ case UWB_RC_CMD_SCAN:
+ result = hwarc_filter_cmd_scan_WUSB_0100(rc, header, size);
+ break;
+ case UWB_RC_CMD_SET_DRP_IE:
+ result = hwarc_filter_cmd_set_drp_ie_WUSB_0100(rc, header, size);
+ break;
+ default:
+ result = -ENOANO;
+ break;
+ }
+ return result;
+}
+
+
+/**
+ * Filter data from WHCI driver to WUSB device
+ *
+ * @header: WHCI 0.95 compliant command from driver
+ * @size: length of command
+ *
+ * Filter commands based on which protocol the device supports. The WUSB
+ * errata should be the same as WHCI 0.95 so we do not filter that here -
+ * only WUSB 1.0.
+ */
+static
+int hwarc_filter_cmd(struct uwb_rc *rc, struct uwb_rccb **header,
+ size_t *size)
+{
+ int result = -ENOANO;
+ if (rc->version == 0x0100)
+ result = hwarc_filter_cmd_WUSB_0100(rc, header, size);
+ return result;
+}
+
+
+/**
+ * Compute return value as sum of incoming value and value at given offset
+ *
+ * @rceb: event for which we compute the size, it contains a variable
+ * length field.
+ * @core_size: size of the "non variable" part of the event
+ * @offset: place in event where the length of the variable part is stored
+ * @buf_size: total length of buffer in which event arrived - we need to make
+ * sure we read the offset in memory that is still part of the event
+ */
+static
+ssize_t hwarc_get_event_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
+ size_t core_size, size_t offset,
+ const size_t buf_size)
+{
+ ssize_t size = -ENOSPC;
+ const void *ptr = rceb;
+ size_t type_size = sizeof(__le16);
+ struct device *dev = &rc->uwb_dev.dev;
+
+ if (offset + type_size >= buf_size) {
+ dev_err(dev, "Not enough data to read extra size of event "
+ "0x%02x/%04x/%02x, only got %zu bytes.\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext, buf_size);
+ goto out;
+ }
+ ptr += offset;
+ size = core_size + le16_to_cpu(*(__le16 *)ptr);
+out:
+ return size;
+}
+
+
+/* Beacon slot change notification (WUSB 1.0 [8.6.3.5]) */
+struct uwb_rc_evt_bp_slot_change_WUSB_0100 {
+ struct uwb_rceb rceb;
+ u8 bSlotNumber;
+} __attribute__((packed));
+
+
+/**
+ * Filter data from WUSB device to WHCI driver
+ *
+ * @header: incoming event
+ * @buf_size: size of buffer in which event arrived
+ * @_event_size: actual size of event in the buffer
+ * @new_size: size of event after filtered
+ *
+ * We don't know how the buffer is constructed - there may be more than one
+ * event in it so buffer length does not determine event length. We first
+ * determine the expected size of the incoming event. This value is passed
+ * back only if the actual filtering succeeded (so we know the computed
+ * expected size is correct). This value will be zero if
+ * the event did not need any filtering.
+ *
+ * WHCI interprets the BP Slot Change event's data differently than
+ * WUSB. The event sizes are exactly the same. The data field
+ * indicates the new beacon slot in which a RC is transmitting its
+ * beacon. The maximum value of this is 96 (wMacBPLength ECMA-368
+ * 17.16 (Table 117)). We thus know that the WUSB value will not set
+ * the bit bNoSlot, so we don't really do anything (placeholder).
+ */
+static
+int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header,
+ const size_t buf_size, size_t *_real_size,
+ size_t *_new_size)
+{
+ int result = -ENOANO;
+ struct uwb_rceb *rceb = *header;
+ int event = le16_to_cpu(rceb->wEvent);
+ ssize_t event_size;
+ size_t core_size, offset;
+
+ if (rceb->bEventType != UWB_RC_CET_GENERAL)
+ goto out;
+ switch (event) {
+ case UWB_RC_EVT_BEACON:
+ core_size = sizeof(struct uwb_rc_evt_beacon_WUSB_0100);
+ offset = offsetof(struct uwb_rc_evt_beacon_WUSB_0100,
+ wBeaconInfoLength);
+ event_size = hwarc_get_event_size(rc, rceb, core_size,
+ offset, buf_size);
+ if (event_size < 0)
+ goto out;
+ *_real_size = event_size;
+ result = hwarc_filter_evt_beacon_WUSB_0100(rc, header,
+ buf_size, _new_size);
+ break;
+ case UWB_RC_EVT_BP_SLOT_CHANGE:
+ *_new_size = *_real_size =
+ sizeof(struct uwb_rc_evt_bp_slot_change_WUSB_0100);
+ result = 0;
+ break;
+
+ case UWB_RC_EVT_DRP_AVAIL:
+ core_size = sizeof(struct uwb_rc_evt_drp_avail_WUSB_0100);
+ offset = offsetof(struct uwb_rc_evt_drp_avail_WUSB_0100,
+ wIELength);
+ event_size = hwarc_get_event_size(rc, rceb, core_size,
+ offset, buf_size);
+ if (event_size < 0)
+ goto out;
+ *_real_size = event_size;
+ result = hwarc_filter_evt_drp_avail_WUSB_0100(
+ rc, header, buf_size, _new_size);
+ break;
+
+ case UWB_RC_EVT_DRP:
+ core_size = sizeof(struct uwb_rc_evt_drp_WUSB_0100);
+ offset = offsetof(struct uwb_rc_evt_drp_WUSB_0100, wIELength);
+ event_size = hwarc_get_event_size(rc, rceb, core_size,
+ offset, buf_size);
+ if (event_size < 0)
+ goto out;
+ *_real_size = event_size;
+ result = hwarc_filter_evt_drp_WUSB_0100(rc, header,
+ buf_size, _new_size);
+ break;
+
+ default:
+ break;
+ }
+out:
+ return result;
+}
+
+/**
+ * Filter data from WUSB device to WHCI driver
+ *
+ * @header: incoming event
+ * @buf_size: size of buffer in which event arrived
+ * @_event_size: actual size of event in the buffer
+ * @_new_size: size of event after filtered
+ *
+ * Filter events based on which protocol the device supports. The WUSB
+ * errata should be the same as WHCI 0.95 so we do not filter that here -
+ * only WUSB 1.0.
+ *
+ * If we don't handle it, we return -ENOANO (why the weird error code?
+ * well, so if I get it, I can pinpoint in the code that raised
+ * it...after all, not too many places use the higher error codes).
+ */
+static
+int hwarc_filter_event(struct uwb_rc *rc, struct uwb_rceb **header,
+ const size_t buf_size, size_t *_real_size,
+ size_t *_new_size)
+{
+ int result = -ENOANO;
+ if (rc->version == 0x0100)
+ result = hwarc_filter_event_WUSB_0100(
+ rc, header, buf_size, _real_size, _new_size);
+ return result;
+}
+
+
+/**
+ * Execute an UWB RC command on HWA
+ *
+ * @rc: Instance of a Radio Controller that is a HWA
+ * @cmd: Buffer containing the RCCB and payload to execute
+ * @cmd_size: Size of the command buffer.
+ *
+ * NOTE: rc's mutex has to be locked
+ */
+static
+int hwarc_cmd(struct uwb_rc *uwb_rc, const struct uwb_rccb *cmd, size_t cmd_size)
+{
+ struct hwarc *hwarc = uwb_rc->priv;
+ return usb_control_msg(
+ hwarc->usb_dev, usb_sndctrlpipe(hwarc->usb_dev, 0),
+ WA_EXEC_RC_CMD, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, hwarc->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ (void *) cmd, cmd_size, 100 /* FIXME: this is totally arbitrary */);
+}
+
+static
+int hwarc_reset(struct uwb_rc *uwb_rc)
+{
+ struct hwarc *hwarc = uwb_rc->priv;
+ int result;
+
+ /* device lock must be held when calling usb_reset_device. */
+ result = usb_lock_device_for_reset(hwarc->usb_dev, NULL);
+ if (result >= 0) {
+ result = usb_reset_device(hwarc->usb_dev);
+ usb_unlock_device(hwarc->usb_dev);
+ }
+
+ return result;
+}
+
+/**
+ * Callback for the notification and event endpoint
+ *
+ * Check's that everything is fine and then passes the read data to
+ * the notification/event handling mechanism (neh).
+ */
+static
+void hwarc_neep_cb(struct urb *urb)
+{
+ struct hwarc *hwarc = urb->context;
+ struct usb_interface *usb_iface = hwarc->usb_iface;
+ struct device *dev = &usb_iface->dev;
+ int result;
+
+ switch (result = urb->status) {
+ case 0:
+ uwb_rc_neh_grok(hwarc->uwb_rc, urb->transfer_buffer,
+ urb->actual_length);
+ break;
+ case -ECONNRESET: /* Not an error, but a controlled situation; */
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ goto out;
+ case -ESHUTDOWN: /* going away! */
+ goto out;
+ default: /* On general errors, retry unless it gets ugly */
+ if (edc_inc(&hwarc->neep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME))
+ goto error_exceeded;
+ dev_err(dev, "NEEP: URB error %d\n", urb->status);
+ }
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result < 0 && result != -ENODEV && result != -EPERM) {
+ /* ignoring unrecoverable errors */
+ dev_err(dev, "NEEP: Can't resubmit URB (%d) resetting device\n",
+ result);
+ goto error;
+ }
+out:
+ return;
+
+error_exceeded:
+ dev_err(dev, "NEEP: URB max acceptable errors "
+ "exceeded, resetting device\n");
+error:
+ uwb_rc_neh_error(hwarc->uwb_rc, result);
+ uwb_rc_reset_all(hwarc->uwb_rc);
+ return;
+}
+
+static void hwarc_init(struct hwarc *hwarc)
+{
+ edc_init(&hwarc->neep_edc);
+}
+
+/**
+ * Initialize the notification/event endpoint stuff
+ *
+ * Note this is effectively a parallel thread; it knows that
+ * hwarc->uwb_rc always exists because the existence of a 'hwarc'
+ * means that there is a reverence on the hwarc->uwb_rc (see
+ * _probe()), and thus _neep_cb() can execute safely.
+ */
+static int hwarc_neep_init(struct uwb_rc *rc)
+{
+ struct hwarc *hwarc = rc->priv;
+ struct usb_interface *iface = hwarc->usb_iface;
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+ struct device *dev = &iface->dev;
+ int result;
+ struct usb_endpoint_descriptor *epd;
+
+ epd = &iface->cur_altsetting->endpoint[0].desc;
+ hwarc->rd_buffer = (void *) __get_free_page(GFP_KERNEL);
+ if (hwarc->rd_buffer == NULL) {
+ dev_err(dev, "Unable to allocate notification's read buffer\n");
+ goto error_rd_buffer;
+ }
+ hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (hwarc->neep_urb == NULL)
+ goto error_urb_alloc;
+ usb_fill_int_urb(hwarc->neep_urb, usb_dev,
+ usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
+ hwarc->rd_buffer, PAGE_SIZE,
+ hwarc_neep_cb, hwarc, epd->bInterval);
+ result = usb_submit_urb(hwarc->neep_urb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "Cannot submit notification URB: %d\n", result);
+ goto error_neep_submit;
+ }
+ return 0;
+
+error_neep_submit:
+ usb_free_urb(hwarc->neep_urb);
+ hwarc->neep_urb = NULL;
+error_urb_alloc:
+ free_page((unsigned long)hwarc->rd_buffer);
+ hwarc->rd_buffer = NULL;
+error_rd_buffer:
+ return -ENOMEM;
+}
+
+
+/** Clean up all the notification endpoint resources */
+static void hwarc_neep_release(struct uwb_rc *rc)
+{
+ struct hwarc *hwarc = rc->priv;
+
+ usb_kill_urb(hwarc->neep_urb);
+ usb_free_urb(hwarc->neep_urb);
+ hwarc->neep_urb = NULL;
+
+ free_page((unsigned long)hwarc->rd_buffer);
+ hwarc->rd_buffer = NULL;
+}
+
+/**
+ * Get the version from class-specific descriptor
+ *
+ * NOTE: this descriptor comes with the big bundled configuration
+ * descriptor that includes the interfaces' and endpoints', so
+ * we just look for it in the cached copy kept by the USB stack.
+ *
+ * NOTE2: We convert LE fields to CPU order.
+ */
+static int hwarc_get_version(struct uwb_rc *rc)
+{
+ int result;
+
+ struct hwarc *hwarc = rc->priv;
+ struct uwb_rc_control_intf_class_desc *descr;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct usb_device *usb_dev = hwarc->usb_dev;
+ char *itr;
+ struct usb_descriptor_header *hdr;
+ size_t itr_size, actconfig_idx;
+ u16 version;
+
+ actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
+ sizeof(usb_dev->config[0]);
+ itr = usb_dev->rawdescriptors[actconfig_idx];
+ itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+ while (itr_size >= sizeof(*hdr)) {
+ hdr = (struct usb_descriptor_header *) itr;
+ dev_dbg(dev, "Extra device descriptor: "
+ "type %02x/%u bytes @ %zu (%zu left)\n",
+ hdr->bDescriptorType, hdr->bLength,
+ (itr - usb_dev->rawdescriptors[actconfig_idx]),
+ itr_size);
+ if (hdr->bDescriptorType == USB_DT_CS_RADIO_CONTROL)
+ goto found;
+ itr += hdr->bLength;
+ itr_size -= hdr->bLength;
+ }
+ dev_err(dev, "cannot find Radio Control Interface Class descriptor\n");
+ return -ENODEV;
+
+found:
+ result = -EINVAL;
+ if (hdr->bLength > itr_size) { /* is it available? */
+ dev_err(dev, "incomplete Radio Control Interface Class "
+ "descriptor (%zu bytes left, %u needed)\n",
+ itr_size, hdr->bLength);
+ goto error;
+ }
+ if (hdr->bLength < sizeof(*descr)) {
+ dev_err(dev, "short Radio Control Interface Class "
+ "descriptor\n");
+ goto error;
+ }
+ descr = (struct uwb_rc_control_intf_class_desc *) hdr;
+ /* Make LE fields CPU order */
+ version = __le16_to_cpu(descr->bcdRCIVersion);
+ if (version != 0x0100) {
+ dev_err(dev, "Device reports protocol version 0x%04x. We "
+ "do not support that. \n", version);
+ result = -EINVAL;
+ goto error;
+ }
+ rc->version = version;
+ dev_dbg(dev, "Device supports WUSB protocol version 0x%04x \n", rc->version);
+ result = 0;
+error:
+ return result;
+}
+
+/*
+ * By creating a 'uwb_rc', we have a reference on it -- that reference
+ * is the one we drop when we disconnect.
+ *
+ * No need to switch altsettings; according to WUSB1.0[8.6.1.1], there
+ * is only one altsetting allowed.
+ */
+static int hwarc_probe(struct usb_interface *iface,
+ const struct usb_device_id *id)
+{
+ int result;
+ struct uwb_rc *uwb_rc;
+ struct hwarc *hwarc;
+ struct device *dev = &iface->dev;
+
+ if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+ return -ENODEV;
+ if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc))
+ return -ENODEV;
+
+ result = -ENOMEM;
+ uwb_rc = uwb_rc_alloc();
+ if (uwb_rc == NULL) {
+ dev_err(dev, "unable to allocate RC instance\n");
+ goto error_rc_alloc;
+ }
+ hwarc = kzalloc(sizeof(*hwarc), GFP_KERNEL);
+ if (hwarc == NULL) {
+ dev_err(dev, "unable to allocate HWA RC instance\n");
+ goto error_alloc;
+ }
+ hwarc_init(hwarc);
+ hwarc->usb_dev = usb_get_dev(interface_to_usbdev(iface));
+ hwarc->usb_iface = usb_get_intf(iface);
+ hwarc->uwb_rc = uwb_rc;
+
+ uwb_rc->owner = THIS_MODULE;
+ uwb_rc->start = hwarc_neep_init;
+ uwb_rc->stop = hwarc_neep_release;
+ uwb_rc->cmd = hwarc_cmd;
+ uwb_rc->reset = hwarc_reset;
+ if (id->driver_info & WUSB_QUIRK_WHCI_CMD_EVT) {
+ uwb_rc->filter_cmd = NULL;
+ uwb_rc->filter_event = NULL;
+ } else {
+ uwb_rc->filter_cmd = hwarc_filter_cmd;
+ uwb_rc->filter_event = hwarc_filter_event;
+ }
+
+ result = uwb_rc_add(uwb_rc, dev, hwarc);
+ if (result < 0)
+ goto error_rc_add;
+ result = hwarc_get_version(uwb_rc);
+ if (result < 0) {
+ dev_err(dev, "cannot retrieve version of RC \n");
+ goto error_get_version;
+ }
+ usb_set_intfdata(iface, hwarc);
+ return 0;
+
+error_get_version:
+ uwb_rc_rm(uwb_rc);
+error_rc_add:
+ usb_put_intf(iface);
+ usb_put_dev(hwarc->usb_dev);
+ kfree(hwarc);
+error_alloc:
+ uwb_rc_put(uwb_rc);
+error_rc_alloc:
+ return result;
+}
+
+static void hwarc_disconnect(struct usb_interface *iface)
+{
+ struct hwarc *hwarc = usb_get_intfdata(iface);
+ struct uwb_rc *uwb_rc = hwarc->uwb_rc;
+
+ usb_set_intfdata(hwarc->usb_iface, NULL);
+ uwb_rc_rm(uwb_rc);
+ usb_put_intf(hwarc->usb_iface);
+ usb_put_dev(hwarc->usb_dev);
+ kfree(hwarc);
+ uwb_rc_put(uwb_rc); /* when creating the device, refcount = 1 */
+}
+
+static int hwarc_pre_reset(struct usb_interface *iface)
+{
+ struct hwarc *hwarc = usb_get_intfdata(iface);
+ struct uwb_rc *uwb_rc = hwarc->uwb_rc;
+
+ uwb_rc_pre_reset(uwb_rc);
+ return 0;
+}
+
+static int hwarc_post_reset(struct usb_interface *iface)
+{
+ struct hwarc *hwarc = usb_get_intfdata(iface);
+ struct uwb_rc *uwb_rc = hwarc->uwb_rc;
+
+ return uwb_rc_post_reset(uwb_rc);
+}
+
+/** USB device ID's that we handle */
+static const struct usb_device_id hwarc_id_table[] = {
+ /* D-Link DUB-1210 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3d02, 0xe0, 0x01, 0x02),
+ .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+ /* Intel i1480 (using firmware 1.3PA2-20070828) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x8086, 0x0c3b, 0xe0, 0x01, 0x02),
+ .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+ /* Alereon 5310 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x01, 0x02),
+ .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+ /* Alereon 5611 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x01, 0x02),
+ .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+ /* Generic match for the Radio Control interface */
+ { USB_INTERFACE_INFO(0xe0, 0x01, 0x02), },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, hwarc_id_table);
+
+static struct usb_driver hwarc_driver = {
+ .name = "hwa-rc",
+ .id_table = hwarc_id_table,
+ .probe = hwarc_probe,
+ .disconnect = hwarc_disconnect,
+ .pre_reset = hwarc_pre_reset,
+ .post_reset = hwarc_post_reset,
+};
+
+module_usb_driver(hwarc_driver);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Host Wireless Adapter Radio Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/i1480/Makefile b/drivers/staging/uwb/i1480/Makefile
new file mode 100644
index 000000000000..d26fb9b845ae
--- /dev/null
+++ b/drivers/staging/uwb/i1480/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o
diff --git a/drivers/staging/uwb/i1480/dfu/Makefile b/drivers/staging/uwb/i1480/dfu/Makefile
new file mode 100644
index 000000000000..4739fdac5922
--- /dev/null
+++ b/drivers/staging/uwb/i1480/dfu/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_UWB_I1480U) += i1480-dfu-usb.o
+
+i1480-dfu-usb-objs := \
+ dfu.o \
+ mac.o \
+ phy.o \
+ usb.o
+
+
diff --git a/drivers/staging/uwb/i1480/dfu/dfu.c b/drivers/staging/uwb/i1480/dfu/dfu.c
new file mode 100644
index 000000000000..9d51ce8faad1
--- /dev/null
+++ b/drivers/staging/uwb/i1480/dfu/dfu.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Wireless UWB Link 1480
+ * Main driver
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Common code for firmware upload used by the USB and PCI version;
+ * i1480_fw_upload() takes a device descriptor and uses the function
+ * pointers it provides to upload firmware and prepare the PHY.
+ *
+ * As well, provides common functions used by the rest of the code.
+ */
+#include "i1480-dfu.h"
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/random.h>
+#include <linux/export.h>
+#include "../../uwb.h"
+
+/*
+ * i1480_rceb_check - Check RCEB for expected field values
+ * @i1480: pointer to device for which RCEB is being checked
+ * @rceb: RCEB being checked
+ * @cmd: which command the RCEB is related to
+ * @context: expected context
+ * @expected_type: expected event type
+ * @expected_event: expected event
+ *
+ * If @cmd is NULL, do not print error messages, but still return an error
+ * code.
+ *
+ * Return 0 if @rceb matches the expected values, -EINVAL otherwise.
+ */
+int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb,
+ const char *cmd, u8 context, u8 expected_type,
+ unsigned expected_event)
+{
+ int result = 0;
+ struct device *dev = i1480->dev;
+ if (rceb->bEventContext != context) {
+ if (cmd)
+ dev_err(dev, "%s: unexpected context id 0x%02x "
+ "(expected 0x%02x)\n", cmd,
+ rceb->bEventContext, context);
+ result = -EINVAL;
+ }
+ if (rceb->bEventType != expected_type) {
+ if (cmd)
+ dev_err(dev, "%s: unexpected event type 0x%02x "
+ "(expected 0x%02x)\n", cmd,
+ rceb->bEventType, expected_type);
+ result = -EINVAL;
+ }
+ if (le16_to_cpu(rceb->wEvent) != expected_event) {
+ if (cmd)
+ dev_err(dev, "%s: unexpected event 0x%04x "
+ "(expected 0x%04x)\n", cmd,
+ le16_to_cpu(rceb->wEvent), expected_event);
+ result = -EINVAL;
+ }
+ return result;
+}
+EXPORT_SYMBOL_GPL(i1480_rceb_check);
+
+
+/*
+ * Execute a Radio Control Command
+ *
+ * Command data has to be in i1480->cmd_buf.
+ *
+ * @returns size of the reply data filled in i1480->evt_buf or < 0 errno
+ * code on error.
+ */
+ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size,
+ size_t reply_size)
+{
+ ssize_t result;
+ struct uwb_rceb *reply = i1480->evt_buf;
+ struct uwb_rccb *cmd = i1480->cmd_buf;
+ u16 expected_event = reply->wEvent;
+ u8 expected_type = reply->bEventType;
+ u8 context;
+
+ init_completion(&i1480->evt_complete);
+ i1480->evt_result = -EINPROGRESS;
+ do {
+ get_random_bytes(&context, 1);
+ } while (context == 0x00 || context == 0xff);
+ cmd->bCommandContext = context;
+ result = i1480->cmd(i1480, cmd_name, cmd_size);
+ if (result < 0)
+ goto error;
+ /* wait for the callback to report a event was received */
+ result = wait_for_completion_interruptible_timeout(
+ &i1480->evt_complete, HZ);
+ if (result == 0) {
+ result = -ETIMEDOUT;
+ goto error;
+ }
+ if (result < 0)
+ goto error;
+ result = i1480->evt_result;
+ if (result < 0) {
+ dev_err(i1480->dev, "%s: command reply reception failed: %zd\n",
+ cmd_name, result);
+ goto error;
+ }
+ /*
+ * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a
+ * spurious notification after firmware is downloaded. So check whether
+ * the receibed RCEB is such notification before assuming that the
+ * command has failed.
+ */
+ if (i1480_rceb_check(i1480, i1480->evt_buf, NULL,
+ 0, 0xfd, 0x0022) == 0) {
+ /* Now wait for the actual RCEB for this command. */
+ result = i1480->wait_init_done(i1480);
+ if (result < 0)
+ goto error;
+ result = i1480->evt_result;
+ }
+ if (result != reply_size) {
+ dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n",
+ cmd_name, result, reply_size);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Verify we got the right event in response */
+ result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context,
+ expected_type, expected_event);
+error:
+ return result;
+}
+EXPORT_SYMBOL_GPL(i1480_cmd);
+
+
+static
+int i1480_print_state(struct i1480 *i1480)
+{
+ int result;
+ u32 *buf = (u32 *) i1480->cmd_buf;
+
+ result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf));
+ if (result < 0) {
+ dev_err(i1480->dev, "cannot read U & L states: %d\n", result);
+ goto error;
+ }
+ dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]);
+error:
+ return result;
+}
+
+
+/*
+ * PCI probe, firmware uploader
+ *
+ * _mac_fw_upload() will call rc_setup(), which needs an rc_release().
+ */
+int i1480_fw_upload(struct i1480 *i1480)
+{
+ int result;
+
+ result = i1480_pre_fw_upload(i1480); /* PHY pre fw */
+ if (result < 0 && result != -ENOENT) {
+ i1480_print_state(i1480);
+ goto error;
+ }
+ result = i1480_mac_fw_upload(i1480); /* MAC fw */
+ if (result < 0) {
+ if (result == -ENOENT)
+ dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n",
+ i1480->mac_fw_name);
+ else
+ i1480_print_state(i1480);
+ goto error;
+ }
+ result = i1480_phy_fw_upload(i1480); /* PHY fw */
+ if (result < 0 && result != -ENOENT) {
+ i1480_print_state(i1480);
+ goto error_rc_release;
+ }
+ /*
+ * FIXME: find some reliable way to check whether firmware is running
+ * properly. Maybe use some standard request that has no side effects?
+ */
+ dev_info(i1480->dev, "firmware uploaded successfully\n");
+error_rc_release:
+ if (i1480->rc_release)
+ i1480->rc_release(i1480);
+ result = 0;
+error:
+ return result;
+}
+EXPORT_SYMBOL_GPL(i1480_fw_upload);
diff --git a/drivers/staging/uwb/i1480/dfu/i1480-dfu.h b/drivers/staging/uwb/i1480/dfu/i1480-dfu.h
new file mode 100644
index 000000000000..b21d058ecc23
--- /dev/null
+++ b/drivers/staging/uwb/i1480/dfu/i1480-dfu.h
@@ -0,0 +1,246 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * i1480 Device Firmware Upload
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This driver is the firmware uploader for the Intel Wireless UWB
+ * Link 1480 device (both in the USB and PCI incarnations).
+ *
+ * The process is quite simple: we stop the device, write the firmware
+ * to its memory and then restart it. Wait for the device to let us
+ * know it is done booting firmware. Ready.
+ *
+ * We might have to upload before or after a phy firmware (which might
+ * be done in two methods, using a normal firmware image or through
+ * the MPI port).
+ *
+ * Because USB and PCI use common methods, we just make ops out of the
+ * common operations (read, write, wait_init_done and cmd) and
+ * implement them in usb.c and pci.c.
+ *
+ * The flow is (some parts omitted):
+ *
+ * i1480_{usb,pci}_probe() On enumerate/discovery
+ * i1480_fw_upload()
+ * i1480_pre_fw_upload()
+ * __mac_fw_upload()
+ * fw_hdrs_load()
+ * mac_fw_hdrs_push()
+ * i1480->write() [i1480_{usb,pci}_write()]
+ * i1480_fw_cmp()
+ * i1480->read() [i1480_{usb,pci}_read()]
+ * i1480_mac_fw_upload()
+ * __mac_fw_upload()
+ * i1480->setup(()
+ * i1480->wait_init_done()
+ * i1480_cmd_reset()
+ * i1480->cmd() [i1480_{usb,pci}_cmd()]
+ * ...
+ * i1480_phy_fw_upload()
+ * request_firmware()
+ * i1480_mpi_write()
+ * i1480->cmd() [i1480_{usb,pci}_cmd()]
+ *
+ * Once the probe function enumerates the device and uploads the
+ * firmware, we just exit with -ENODEV, as we don't really want to
+ * attach to the device.
+ */
+#ifndef __i1480_DFU_H__
+#define __i1480_DFU_H__
+
+#include <linux/types.h>
+#include <linux/completion.h>
+#include "../../include/spec.h"
+
+#define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018))
+
+#if i1480_FW > 0x00000302
+#define i1480_RCEB_EXTENDED
+#endif
+
+struct uwb_rccb;
+struct uwb_rceb;
+
+/*
+ * Common firmware upload handlers
+ *
+ * Normally you embed this struct in another one specific to your hw.
+ *
+ * @write Write to device's memory from buffer.
+ * @read Read from device's memory to i1480->evt_buf.
+ * @setup Setup device after basic firmware is uploaded
+ * @wait_init_done
+ * Wait for the device to send a notification saying init
+ * is done.
+ * @cmd FOP for issuing the command to the hardware. The
+ * command data is contained in i1480->cmd_buf and the size
+ * is supplied as an argument. The command replied is put
+ * in i1480->evt_buf and the size in i1480->evt_result (or if
+ * an error, a < 0 errno code).
+ *
+ * @cmd_buf Memory buffer used to send commands to the device.
+ * Allocated by the upper layers i1480_fw_upload().
+ * Size has to be @buf_size.
+ * @evt_buf Memory buffer used to place the async notifications
+ * received by the hw. Allocated by the upper layers
+ * i1480_fw_upload().
+ * Size has to be @buf_size.
+ * @cmd_complete
+ * Low level driver uses this to notify code waiting afor
+ * an event that the event has arrived and data is in
+ * i1480->evt_buf (and size/result in i1480->evt_result).
+ * @hw_rev
+ * Use this value to activate dfu code to support new revisions
+ * of hardware. i1480_init() sets this to a default value.
+ * It should be updated by the USB and PCI code.
+ */
+struct i1480 {
+ struct device *dev;
+
+ int (*write)(struct i1480 *, u32 addr, const void *, size_t);
+ int (*read)(struct i1480 *, u32 addr, size_t);
+ int (*rc_setup)(struct i1480 *);
+ void (*rc_release)(struct i1480 *);
+ int (*wait_init_done)(struct i1480 *);
+ int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size);
+ const char *pre_fw_name;
+ const char *mac_fw_name;
+ const char *mac_fw_name_deprecate; /* FIXME: Will go away */
+ const char *phy_fw_name;
+ u8 hw_rev;
+
+ size_t buf_size; /* size of both evt_buf and cmd_buf */
+ void *evt_buf, *cmd_buf;
+ ssize_t evt_result;
+ struct completion evt_complete;
+};
+
+static inline
+void i1480_init(struct i1480 *i1480)
+{
+ i1480->hw_rev = 1;
+ init_completion(&i1480->evt_complete);
+}
+
+extern int i1480_fw_upload(struct i1480 *);
+extern int i1480_pre_fw_upload(struct i1480 *);
+extern int i1480_mac_fw_upload(struct i1480 *);
+extern int i1480_phy_fw_upload(struct i1480 *);
+extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t);
+extern int i1480_rceb_check(const struct i1480 *,
+ const struct uwb_rceb *, const char *, u8,
+ u8, unsigned);
+
+enum {
+ /* Vendor specific command type */
+ i1480_CET_VS1 = 0xfd,
+ /* i1480 commands */
+ i1480_CMD_SET_IP_MAS = 0x000e,
+ i1480_CMD_GET_MAC_PHY_INFO = 0x0003,
+ i1480_CMD_MPI_WRITE = 0x000f,
+ i1480_CMD_MPI_READ = 0x0010,
+ /* i1480 events */
+#if i1480_FW > 0x00000302
+ i1480_EVT_CONFIRM = 0x0002,
+ i1480_EVT_RM_INIT_DONE = 0x0101,
+ i1480_EVT_DEV_ADD = 0x0103,
+ i1480_EVT_DEV_RM = 0x0104,
+ i1480_EVT_DEV_ID_CHANGE = 0x0105,
+ i1480_EVT_GET_MAC_PHY_INFO = i1480_CMD_GET_MAC_PHY_INFO,
+#else
+ i1480_EVT_CONFIRM = 0x0002,
+ i1480_EVT_RM_INIT_DONE = 0x0101,
+ i1480_EVT_DEV_ADD = 0x0103,
+ i1480_EVT_DEV_RM = 0x0104,
+ i1480_EVT_DEV_ID_CHANGE = 0x0105,
+ i1480_EVT_GET_MAC_PHY_INFO = i1480_EVT_CONFIRM,
+#endif
+};
+
+
+struct i1480_evt_confirm {
+ struct uwb_rceb rceb;
+#ifdef i1480_RCEB_EXTENDED
+ __le16 wParamLength;
+#endif
+ u8 bResultCode;
+} __attribute__((packed));
+
+
+struct i1480_rceb {
+ struct uwb_rceb rceb;
+#ifdef i1480_RCEB_EXTENDED
+ __le16 wParamLength;
+#endif
+} __attribute__((packed));
+
+
+/**
+ * Get MAC & PHY Information confirm event structure
+ *
+ * Confirm event returned by the command.
+ */
+struct i1480_evt_confirm_GMPI {
+#if i1480_FW > 0x00000302
+ struct uwb_rceb rceb;
+ __le16 wParamLength;
+ __le16 status;
+ u8 mac_addr[6]; /* EUI-64 bit IEEE address [still 8 bytes?] */
+ u8 dev_addr[2];
+ __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */
+ u8 hw_rev;
+ u8 phy_vendor;
+ u8 phy_rev; /* major v = >> 8; minor = v & 0xff */
+ __le16 mac_caps;
+ u8 phy_caps[3];
+ u8 key_stores;
+ __le16 mcast_addr_stores;
+ u8 sec_mode_supported;
+#else
+ struct uwb_rceb rceb;
+ u8 status;
+ u8 mac_addr[8]; /* EUI-64 bit IEEE address [still 8 bytes?] */
+ u8 dev_addr[2];
+ __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */
+ __le16 phy_fw_rev; /* major v = >> 8; minor = v & 0xff */
+ __le16 mac_caps;
+ u8 phy_caps;
+ u8 key_stores;
+ __le16 mcast_addr_stores;
+ u8 sec_mode_supported;
+#endif
+} __attribute__((packed));
+
+
+struct i1480_cmd_mpi_write {
+ struct uwb_rccb rccb;
+ __le16 size;
+ u8 data[];
+};
+
+
+struct i1480_cmd_mpi_read {
+ struct uwb_rccb rccb;
+ __le16 size;
+ struct {
+ u8 page, offset;
+ } __attribute__((packed)) data[];
+} __attribute__((packed));
+
+
+struct i1480_evt_mpi_read {
+ struct uwb_rceb rceb;
+#ifdef i1480_RCEB_EXTENDED
+ __le16 wParamLength;
+#endif
+ u8 bResultCode;
+ __le16 size;
+ struct {
+ u8 page, offset, value;
+ } __attribute__((packed)) data[];
+} __attribute__((packed));
+
+
+#endif /* #ifndef __i1480_DFU_H__ */
diff --git a/drivers/staging/uwb/i1480/dfu/mac.c b/drivers/staging/uwb/i1480/dfu/mac.c
new file mode 100644
index 000000000000..6e4d6c9cecf5
--- /dev/null
+++ b/drivers/staging/uwb/i1480/dfu/mac.c
@@ -0,0 +1,496 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Wireless UWB Link 1480
+ * MAC Firmware upload implementation
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Implementation of the code for parsing the firmware file (extract
+ * the headers and binary code chunks) in the fw_*() functions. The
+ * code to upload pre and mac firmwares is the same, so it uses a
+ * common entry point in __mac_fw_upload(), which uses the i1480
+ * function pointers to push the firmware to the device.
+ */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include "../../uwb.h"
+#include "i1480-dfu.h"
+
+/*
+ * Descriptor for a continuous segment of MAC fw data
+ */
+struct fw_hdr {
+ unsigned long address;
+ size_t length;
+ const u32 *bin;
+ struct fw_hdr *next;
+};
+
+
+/* Free a chain of firmware headers */
+static
+void fw_hdrs_free(struct fw_hdr *hdr)
+{
+ struct fw_hdr *next;
+
+ while (hdr) {
+ next = hdr->next;
+ kfree(hdr);
+ hdr = next;
+ }
+}
+
+
+/* Fill a firmware header descriptor from a memory buffer */
+static
+int fw_hdr_load(struct i1480 *i1480, struct fw_hdr *hdr, unsigned hdr_cnt,
+ const char *_data, const u32 *data_itr, const u32 *data_top)
+{
+ size_t hdr_offset = (const char *) data_itr - _data;
+ size_t remaining_size = (void *) data_top - (void *) data_itr;
+ if (data_itr + 2 > data_top) {
+ dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in header at "
+ "offset %zu, limit %zu\n",
+ hdr_cnt, hdr_offset,
+ (const char *) data_itr + 2 - _data,
+ (const char *) data_top - _data);
+ return -EINVAL;
+ }
+ hdr->next = NULL;
+ hdr->address = le32_to_cpu(*data_itr++);
+ hdr->length = le32_to_cpu(*data_itr++);
+ hdr->bin = data_itr;
+ if (hdr->length > remaining_size) {
+ dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in data; "
+ "chunk too long (%zu bytes), only %zu left\n",
+ hdr_cnt, hdr_offset, hdr->length, remaining_size);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+/**
+ * Get a buffer where the firmware is supposed to be and create a
+ * chain of headers linking them together.
+ *
+ * @phdr: where to place the pointer to the first header (headers link
+ * to the next via the @hdr->next ptr); need to free the whole
+ * chain when done.
+ *
+ * @_data: Pointer to the data buffer.
+ *
+ * @_data_size: Size of the data buffer (bytes); data size has to be a
+ * multiple of 4. Function will fail if not.
+ *
+ * Goes over the whole binary blob; reads the first chunk and creates
+ * a fw hdr from it (which points to where the data is in @_data and
+ * the length of the chunk); then goes on to the next chunk until
+ * done. Each header is linked to the next.
+ */
+static
+int fw_hdrs_load(struct i1480 *i1480, struct fw_hdr **phdr,
+ const char *_data, size_t data_size)
+{
+ int result;
+ unsigned hdr_cnt = 0;
+ u32 *data = (u32 *) _data, *data_itr, *data_top;
+ struct fw_hdr *hdr, **prev_hdr = phdr;
+
+ result = -EINVAL;
+ /* Check size is ok and pointer is aligned */
+ if (data_size % sizeof(u32) != 0)
+ goto error;
+ if ((unsigned long) _data % sizeof(u16) != 0)
+ goto error;
+ *phdr = NULL;
+ data_itr = data;
+ data_top = (u32 *) (_data + data_size);
+ while (data_itr < data_top) {
+ result = -ENOMEM;
+ hdr = kmalloc(sizeof(*hdr), GFP_KERNEL);
+ if (hdr == NULL) {
+ dev_err(i1480->dev, "Cannot allocate fw header "
+ "for chunk #%u\n", hdr_cnt);
+ goto error_alloc;
+ }
+ result = fw_hdr_load(i1480, hdr, hdr_cnt,
+ _data, data_itr, data_top);
+ if (result < 0)
+ goto error_load;
+ data_itr += 2 + hdr->length;
+ *prev_hdr = hdr;
+ prev_hdr = &hdr->next;
+ hdr_cnt++;
+ };
+ *prev_hdr = NULL;
+ return 0;
+
+error_load:
+ kfree(hdr);
+error_alloc:
+ fw_hdrs_free(*phdr);
+error:
+ return result;
+}
+
+
+/**
+ * Compares a chunk of fw with one in the devices's memory
+ *
+ * @i1480: Device instance
+ * @hdr: Pointer to the firmware chunk
+ * @returns: 0 if equal, < 0 errno on error. If > 0, it is the offset
+ * where the difference was found (plus one).
+ *
+ * Kind of dirty and simplistic, but does the trick in both the PCI
+ * and USB version. We do a quick[er] memcmp(), and if it fails, we do
+ * a byte-by-byte to find the offset.
+ */
+static
+ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr)
+{
+ ssize_t result = 0;
+ u32 src_itr = 0, cnt;
+ size_t size = hdr->length*sizeof(hdr->bin[0]);
+ size_t chunk_size;
+ u8 *bin = (u8 *) hdr->bin;
+
+ while (size > 0) {
+ chunk_size = size < i1480->buf_size ? size : i1480->buf_size;
+ result = i1480->read(i1480, hdr->address + src_itr, chunk_size);
+ if (result < 0) {
+ dev_err(i1480->dev, "error reading for verification: "
+ "%zd\n", result);
+ goto error;
+ }
+ if (memcmp(i1480->cmd_buf, bin + src_itr, result)) {
+ u8 *buf = i1480->cmd_buf;
+ for (cnt = 0; cnt < result; cnt++)
+ if (bin[src_itr + cnt] != buf[cnt]) {
+ dev_err(i1480->dev, "byte failed at "
+ "src_itr %u cnt %u [0x%02x "
+ "vs 0x%02x]\n", src_itr, cnt,
+ bin[src_itr + cnt], buf[cnt]);
+ result = src_itr + cnt + 1;
+ goto cmp_failed;
+ }
+ }
+ src_itr += result;
+ size -= result;
+ }
+ result = 0;
+error:
+cmp_failed:
+ return result;
+}
+
+
+/**
+ * Writes firmware headers to the device.
+ *
+ * @prd: PRD instance
+ * @hdr: Processed firmware
+ * @returns: 0 if ok, < 0 errno on error.
+ */
+static
+int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr,
+ const char *fw_name, const char *fw_tag)
+{
+ struct device *dev = i1480->dev;
+ ssize_t result = 0;
+ struct fw_hdr *hdr_itr;
+ int verif_retry_count;
+
+ /* Now, header by header, push them to the hw */
+ for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) {
+ verif_retry_count = 0;
+retry:
+ dev_dbg(dev, "fw chunk (%zu @ 0x%08lx)\n",
+ hdr_itr->length * sizeof(hdr_itr->bin[0]),
+ hdr_itr->address);
+ result = i1480->write(i1480, hdr_itr->address, hdr_itr->bin,
+ hdr_itr->length*sizeof(hdr_itr->bin[0]));
+ if (result < 0) {
+ dev_err(dev, "%s fw '%s': write failed (%zuB @ 0x%lx):"
+ " %zd\n", fw_tag, fw_name,
+ hdr_itr->length * sizeof(hdr_itr->bin[0]),
+ hdr_itr->address, result);
+ break;
+ }
+ result = i1480_fw_cmp(i1480, hdr_itr);
+ if (result < 0) {
+ dev_err(dev, "%s fw '%s': verification read "
+ "failed (%zuB @ 0x%lx): %zd\n",
+ fw_tag, fw_name,
+ hdr_itr->length * sizeof(hdr_itr->bin[0]),
+ hdr_itr->address, result);
+ break;
+ }
+ if (result > 0) { /* Offset where it failed + 1 */
+ result--;
+ dev_err(dev, "%s fw '%s': WARNING: verification "
+ "failed at 0x%lx: retrying\n",
+ fw_tag, fw_name, hdr_itr->address + result);
+ if (++verif_retry_count < 3)
+ goto retry; /* write this block again! */
+ dev_err(dev, "%s fw '%s': verification failed at 0x%lx: "
+ "tried %d times\n", fw_tag, fw_name,
+ hdr_itr->address + result, verif_retry_count);
+ result = -EINVAL;
+ break;
+ }
+ }
+ return result;
+}
+
+
+/** Puts the device in firmware upload mode.*/
+static
+int mac_fw_upload_enable(struct i1480 *i1480)
+{
+ int result;
+ u32 reg = 0x800000c0;
+ u32 *buffer = (u32 *)i1480->cmd_buf;
+
+ if (i1480->hw_rev > 1)
+ reg = 0x8000d0d4;
+ result = i1480->read(i1480, reg, sizeof(u32));
+ if (result < 0)
+ goto error_cmd;
+ *buffer &= ~i1480_FW_UPLOAD_MODE_MASK;
+ result = i1480->write(i1480, reg, buffer, sizeof(u32));
+ if (result < 0)
+ goto error_cmd;
+ return 0;
+error_cmd:
+ dev_err(i1480->dev, "can't enable fw upload mode: %d\n", result);
+ return result;
+}
+
+
+/** Gets the device out of firmware upload mode. */
+static
+int mac_fw_upload_disable(struct i1480 *i1480)
+{
+ int result;
+ u32 reg = 0x800000c0;
+ u32 *buffer = (u32 *)i1480->cmd_buf;
+
+ if (i1480->hw_rev > 1)
+ reg = 0x8000d0d4;
+ result = i1480->read(i1480, reg, sizeof(u32));
+ if (result < 0)
+ goto error_cmd;
+ *buffer |= i1480_FW_UPLOAD_MODE_MASK;
+ result = i1480->write(i1480, reg, buffer, sizeof(u32));
+ if (result < 0)
+ goto error_cmd;
+ return 0;
+error_cmd:
+ dev_err(i1480->dev, "can't disable fw upload mode: %d\n", result);
+ return result;
+}
+
+
+
+/**
+ * Generic function for uploading a MAC firmware.
+ *
+ * @i1480: Device instance
+ * @fw_name: Name of firmware file to upload.
+ * @fw_tag: Name of the firmware type (for messages)
+ * [eg: MAC, PRE]
+ * @do_wait: Wait for device to emit initialization done message (0
+ * for PRE fws, 1 for MAC fws).
+ * @returns: 0 if ok, < 0 errno on error.
+ */
+static
+int __mac_fw_upload(struct i1480 *i1480, const char *fw_name,
+ const char *fw_tag)
+{
+ int result;
+ const struct firmware *fw;
+ struct fw_hdr *fw_hdrs;
+
+ result = request_firmware(&fw, fw_name, i1480->dev);
+ if (result < 0) /* Up to caller to complain on -ENOENT */
+ goto out;
+ result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size);
+ if (result < 0) {
+ dev_err(i1480->dev, "%s fw '%s': failed to parse firmware "
+ "file: %d\n", fw_tag, fw_name, result);
+ goto out_release;
+ }
+ result = mac_fw_upload_enable(i1480);
+ if (result < 0)
+ goto out_hdrs_release;
+ result = mac_fw_hdrs_push(i1480, fw_hdrs, fw_name, fw_tag);
+ mac_fw_upload_disable(i1480);
+out_hdrs_release:
+ if (result >= 0)
+ dev_info(i1480->dev, "%s fw '%s': uploaded\n", fw_tag, fw_name);
+ else
+ dev_err(i1480->dev, "%s fw '%s': failed to upload (%d), "
+ "power cycle device\n", fw_tag, fw_name, result);
+ fw_hdrs_free(fw_hdrs);
+out_release:
+ release_firmware(fw);
+out:
+ return result;
+}
+
+
+/**
+ * Upload a pre-PHY firmware
+ *
+ */
+int i1480_pre_fw_upload(struct i1480 *i1480)
+{
+ int result;
+ result = __mac_fw_upload(i1480, i1480->pre_fw_name, "PRE");
+ if (result == 0)
+ msleep(400);
+ return result;
+}
+
+
+/**
+ * Reset a the MAC and PHY
+ *
+ * @i1480: Device's instance
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ *
+ * We issue the reset to make sure the UWB controller reinits the PHY;
+ * this way we can now if the PHY init went ok.
+ */
+static
+int i1480_cmd_reset(struct i1480 *i1480)
+{
+ int result;
+ struct uwb_rccb *cmd = (void *) i1480->cmd_buf;
+ struct i1480_evt_reset {
+ struct uwb_rceb rceb;
+ u8 bResultCode;
+ } __attribute__((packed)) *reply = (void *) i1480->evt_buf;
+
+ result = -ENOMEM;
+ cmd->bCommandType = UWB_RC_CET_GENERAL;
+ cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
+ reply->rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply->rceb.wEvent = UWB_RC_CMD_RESET;
+ result = i1480_cmd(i1480, "RESET", sizeof(*cmd), sizeof(*reply));
+ if (result < 0)
+ goto out;
+ if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(i1480->dev, "RESET: command execution failed: %u\n",
+ reply->bResultCode);
+ result = -EIO;
+ }
+out:
+ return result;
+
+}
+
+
+/* Wait for the MAC FW to start running */
+static
+int i1480_fw_is_running_q(struct i1480 *i1480)
+{
+ int cnt = 0;
+ int result;
+ u32 *val = (u32 *) i1480->cmd_buf;
+
+ for (cnt = 0; cnt < 10; cnt++) {
+ msleep(100);
+ result = i1480->read(i1480, 0x80080000, 4);
+ if (result < 0) {
+ dev_err(i1480->dev, "Can't read 0x8008000: %d\n", result);
+ goto out;
+ }
+ if (*val == 0x55555555UL) /* fw running? cool */
+ goto out;
+ }
+ dev_err(i1480->dev, "Timed out waiting for fw to start\n");
+ result = -ETIMEDOUT;
+out:
+ return result;
+
+}
+
+
+/**
+ * Upload MAC firmware, wait for it to start
+ *
+ * @i1480: Device instance
+ * @fw_name: Name of the file that contains the firmware
+ *
+ * This has to be called after the pre fw has been uploaded (if
+ * there is any).
+ */
+int i1480_mac_fw_upload(struct i1480 *i1480)
+{
+ int result = 0, deprecated_name = 0;
+ struct i1480_rceb *rcebe = (void *) i1480->evt_buf;
+
+ result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC");
+ if (result == -ENOENT) {
+ result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate,
+ "MAC");
+ deprecated_name = 1;
+ }
+ if (result < 0)
+ return result;
+ if (deprecated_name == 1)
+ dev_warn(i1480->dev,
+ "WARNING: firmware file name %s is deprecated, "
+ "please rename to %s\n",
+ i1480->mac_fw_name_deprecate, i1480->mac_fw_name);
+ result = i1480_fw_is_running_q(i1480);
+ if (result < 0)
+ goto error_fw_not_running;
+ result = i1480->rc_setup ? i1480->rc_setup(i1480) : 0;
+ if (result < 0) {
+ dev_err(i1480->dev, "Cannot setup after MAC fw upload: %d\n",
+ result);
+ goto error_setup;
+ }
+ result = i1480->wait_init_done(i1480); /* wait init'on */
+ if (result < 0) {
+ dev_err(i1480->dev, "MAC fw '%s': Initialization timed out "
+ "(%d)\n", i1480->mac_fw_name, result);
+ goto error_init_timeout;
+ }
+ /* verify we got the right initialization done event */
+ if (i1480->evt_result != sizeof(*rcebe)) {
+ dev_err(i1480->dev, "MAC fw '%s': initialization event returns "
+ "wrong size (%zu bytes vs %zu needed)\n",
+ i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe));
+ goto error_size;
+ }
+ result = -EIO;
+ if (i1480_rceb_check(i1480, &rcebe->rceb, NULL, 0, i1480_CET_VS1,
+ i1480_EVT_RM_INIT_DONE) < 0) {
+ dev_err(i1480->dev, "wrong initialization event 0x%02x/%04x/%02x "
+ "received; expected 0x%02x/%04x/00\n",
+ rcebe->rceb.bEventType, le16_to_cpu(rcebe->rceb.wEvent),
+ rcebe->rceb.bEventContext, i1480_CET_VS1,
+ i1480_EVT_RM_INIT_DONE);
+ goto error_init_timeout;
+ }
+ result = i1480_cmd_reset(i1480);
+ if (result < 0)
+ dev_err(i1480->dev, "MAC fw '%s': MBOA reset failed (%d)\n",
+ i1480->mac_fw_name, result);
+error_fw_not_running:
+error_init_timeout:
+error_size:
+error_setup:
+ return result;
+}
diff --git a/drivers/staging/uwb/i1480/dfu/phy.c b/drivers/staging/uwb/i1480/dfu/phy.c
new file mode 100644
index 000000000000..13512c7dda0b
--- /dev/null
+++ b/drivers/staging/uwb/i1480/dfu/phy.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Wireless UWB Link 1480
+ * PHY parameters upload
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Code for uploading the PHY parameters to the PHY through the UWB
+ * Radio Control interface.
+ *
+ * We just send the data through the MPI interface using HWA-like
+ * commands and then reset the PHY to make sure it is ok.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include "../../../wusbcore/include/wusb.h"
+#include "i1480-dfu.h"
+
+
+/**
+ * Write a value array to an address of the MPI interface
+ *
+ * @i1480: Device descriptor
+ * @data: Data array to write
+ * @size: Size of the data array
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * The data array is organized into pairs:
+ *
+ * ADDRESS VALUE
+ *
+ * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has
+ * to be a multiple of three.
+ */
+static
+int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size)
+{
+ int result;
+ struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf;
+ struct i1480_evt_confirm *reply = i1480->evt_buf;
+
+ BUG_ON(size > 480);
+ result = -ENOMEM;
+ cmd->rccb.bCommandType = i1480_CET_VS1;
+ cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE);
+ cmd->size = cpu_to_le16(size);
+ memcpy(cmd->data, data, size);
+ reply->rceb.bEventType = i1480_CET_VS1;
+ reply->rceb.wEvent = i1480_CMD_MPI_WRITE;
+ result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply));
+ if (result < 0)
+ goto out;
+ if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n",
+ reply->bResultCode);
+ result = -EIO;
+ }
+out:
+ return result;
+}
+
+
+/**
+ * Read a value array to from an address of the MPI interface
+ *
+ * @i1480: Device descriptor
+ * @data: where to place the read array
+ * @srcaddr: Where to read from
+ * @size: Size of the data read array
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * The command data array is organized into pairs ADDR0 ADDR1..., and
+ * the returned data in ADDR0 VALUE0 ADDR1 VALUE1...
+ *
+ * We generate the command array to be a sequential read and then
+ * rearrange the result.
+ *
+ * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply.
+ *
+ * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount
+ * of values we can read is (512 - sizeof(*reply)) / 3
+ */
+static
+int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size)
+{
+ int result;
+ struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf;
+ struct i1480_evt_mpi_read *reply = i1480->evt_buf;
+ unsigned cnt;
+
+ memset(i1480->cmd_buf, 0x69, 512);
+ memset(i1480->evt_buf, 0x69, 512);
+
+ BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3);
+ result = -ENOMEM;
+ cmd->rccb.bCommandType = i1480_CET_VS1;
+ cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ);
+ cmd->size = cpu_to_le16(3*size);
+ for (cnt = 0; cnt < size; cnt++) {
+ cmd->data[cnt].page = (srcaddr + cnt) >> 8;
+ cmd->data[cnt].offset = (srcaddr + cnt) & 0xff;
+ }
+ reply->rceb.bEventType = i1480_CET_VS1;
+ reply->rceb.wEvent = i1480_CMD_MPI_READ;
+ result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size,
+ sizeof(*reply) + 3*size);
+ if (result < 0)
+ goto out;
+ if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n",
+ reply->bResultCode);
+ result = -EIO;
+ goto out;
+ }
+ for (cnt = 0; cnt < size; cnt++) {
+ if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
+ dev_err(i1480->dev, "MPI-READ: page inconsistency at "
+ "index %u: expected 0x%02x, got 0x%02x\n", cnt,
+ (srcaddr + cnt) >> 8, reply->data[cnt].page);
+ if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
+ dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
+ "index %u: expected 0x%02x, got 0x%02x\n", cnt,
+ (srcaddr + cnt) & 0x00ff,
+ reply->data[cnt].offset);
+ data[cnt] = reply->data[cnt].value;
+ }
+ result = 0;
+out:
+ return result;
+}
+
+
+/**
+ * Upload a PHY firmware, wait for it to start
+ *
+ * @i1480: Device instance
+ * @fw_name: Name of the file that contains the firmware
+ *
+ * We assume the MAC fw is up and running. This means we can use the
+ * MPI interface to write the PHY firmware. Once done, we issue an
+ * MBOA Reset, which will force the MAC to reset and reinitialize the
+ * PHY. If that works, we are ready to go.
+ *
+ * Max packet size for the MPI write is 512, so the max buffer is 480
+ * (which gives us 160 byte triads of MSB, LSB and VAL for the data).
+ */
+int i1480_phy_fw_upload(struct i1480 *i1480)
+{
+ int result;
+ const struct firmware *fw;
+ const char *data_itr, *data_top;
+ const size_t MAX_BLK_SIZE = 480; /* 160 triads */
+ size_t data_size;
+ u8 phy_stat;
+
+ result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
+ if (result < 0)
+ goto out;
+ /* Loop writing data in chunks as big as possible until done. */
+ for (data_itr = fw->data, data_top = data_itr + fw->size;
+ data_itr < data_top; data_itr += MAX_BLK_SIZE) {
+ data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
+ result = i1480_mpi_write(i1480, data_itr, data_size);
+ if (result < 0)
+ goto error_mpi_write;
+ }
+ /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */
+ result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
+ if (result < 0) {
+ dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
+ goto error_mpi_status;
+ }
+ if (phy_stat != 0) {
+ result = -ENODEV;
+ dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
+ goto error_phy_status;
+ }
+ dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
+error_phy_status:
+error_mpi_status:
+error_mpi_write:
+ release_firmware(fw);
+ if (result < 0)
+ dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
+ "power cycle device\n", i1480->phy_fw_name, result);
+out:
+ return result;
+}
diff --git a/drivers/staging/uwb/i1480/dfu/usb.c b/drivers/staging/uwb/i1480/dfu/usb.c
new file mode 100644
index 000000000000..d41086bdd783
--- /dev/null
+++ b/drivers/staging/uwb/i1480/dfu/usb.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Wireless UWB Link 1480
+ * USB SKU firmware upload implementation
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This driver will prepare the i1480 device to behave as a real
+ * Wireless USB HWA adaptor by uploading the firmware.
+ *
+ * When the device is connected or driver is loaded, i1480_usb_probe()
+ * is called--this will allocate and initialize the device structure,
+ * fill in the pointers to the common functions (read, write,
+ * wait_init_done and cmd for HWA command execution) and once that is
+ * done, call the common firmware uploading routine. Then clean up and
+ * return -ENODEV, as we don't attach to the device.
+ *
+ * The rest are the basic ops we implement that the fw upload code
+ * uses to do its job. All the ops in the common code are i1480->NAME,
+ * the functions are i1480_usb_NAME().
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "../../uwb.h"
+#include "../../../wusbcore/include/wusb.h"
+#include "../../../wusbcore/include/wusb-wa.h"
+#include "i1480-dfu.h"
+
+struct i1480_usb {
+ struct i1480 i1480;
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+ struct urb *neep_urb; /* URB for reading from EP1 */
+};
+
+
+static
+void i1480_usb_init(struct i1480_usb *i1480_usb)
+{
+ i1480_init(&i1480_usb->i1480);
+}
+
+
+static
+int i1480_usb_create(struct i1480_usb *i1480_usb, struct usb_interface *iface)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+ int result = -ENOMEM;
+
+ i1480_usb->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */
+ i1480_usb->usb_iface = usb_get_intf(iface);
+ usb_set_intfdata(iface, i1480_usb); /* Bind the driver to iface0 */
+ i1480_usb->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (i1480_usb->neep_urb == NULL)
+ goto error;
+ return 0;
+
+error:
+ usb_set_intfdata(iface, NULL);
+ usb_put_intf(iface);
+ usb_put_dev(usb_dev);
+ return result;
+}
+
+
+static
+void i1480_usb_destroy(struct i1480_usb *i1480_usb)
+{
+ usb_kill_urb(i1480_usb->neep_urb);
+ usb_free_urb(i1480_usb->neep_urb);
+ usb_set_intfdata(i1480_usb->usb_iface, NULL);
+ usb_put_intf(i1480_usb->usb_iface);
+ usb_put_dev(i1480_usb->usb_dev);
+}
+
+
+/**
+ * Write a buffer to a memory address in the i1480 device
+ *
+ * @i1480: i1480 instance
+ * @memory_address:
+ * Address where to write the data buffer to.
+ * @buffer: Buffer to the data
+ * @size: Size of the buffer [has to be < 512].
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Data buffers to USB cannot be on the stack or in vmalloc'ed areas,
+ * so we copy it to the local i1480 buffer before proceeding. In any
+ * case, we have a max size we can send.
+ */
+static
+int i1480_usb_write(struct i1480 *i1480, u32 memory_address,
+ const void *buffer, size_t size)
+{
+ int result = 0;
+ struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+ size_t buffer_size, itr = 0;
+
+ BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
+ while (size > 0) {
+ buffer_size = size < i1480->buf_size ? size : i1480->buf_size;
+ memcpy(i1480->cmd_buf, buffer + itr, buffer_size);
+ result = usb_control_msg(
+ i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
+ 0xf0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ memory_address, (memory_address >> 16),
+ i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */);
+ if (result < 0)
+ break;
+ itr += result;
+ memory_address += result;
+ size -= result;
+ }
+ return result;
+}
+
+
+/**
+ * Read a block [max size 512] of the device's memory to @i1480's buffer.
+ *
+ * @i1480: i1480 instance
+ * @memory_address:
+ * Address where to read from.
+ * @size: Size to read. Smaller than or equal to 512.
+ * @returns: >= 0 number of bytes written if ok, < 0 errno code on error.
+ *
+ * NOTE: if the memory address or block is incorrect, you might get a
+ * stall or a different memory read. Caller has to verify the
+ * memory address and size passed back in the @neh structure.
+ */
+static
+int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size)
+{
+ ssize_t result = 0, bytes = 0;
+ size_t itr, read_size = i1480->buf_size;
+ struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+
+ BUG_ON(size > i1480->buf_size);
+ BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
+ BUG_ON(read_size > 512);
+
+ if (addr >= 0x8000d200 && addr < 0x8000d400) /* Yeah, HW quirk */
+ read_size = 4;
+
+ for (itr = 0; itr < size; itr += read_size) {
+ size_t itr_addr = addr + itr;
+ size_t itr_size = min(read_size, size - itr);
+ result = usb_control_msg(
+ i1480_usb->usb_dev, usb_rcvctrlpipe(i1480_usb->usb_dev, 0),
+ 0xf0, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ itr_addr, (itr_addr >> 16),
+ i1480->cmd_buf + itr, itr_size,
+ 100 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(i1480->dev, "%s: USB read error: %zd\n",
+ __func__, result);
+ goto out;
+ }
+ if (result != itr_size) {
+ result = -EIO;
+ dev_err(i1480->dev,
+ "%s: partial read got only %zu bytes vs %zu expected\n",
+ __func__, result, itr_size);
+ goto out;
+ }
+ bytes += result;
+ }
+ result = bytes;
+out:
+ return result;
+}
+
+
+/**
+ * Callback for reads on the notification/event endpoint
+ *
+ * Just enables the completion read handler.
+ */
+static
+void i1480_usb_neep_cb(struct urb *urb)
+{
+ struct i1480 *i1480 = urb->context;
+ struct device *dev = i1480->dev;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ECONNRESET: /* Not an error, but a controlled situation; */
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ dev_dbg(dev, "NEEP: reset/noent %d\n", urb->status);
+ break;
+ case -ESHUTDOWN: /* going away! */
+ dev_dbg(dev, "NEEP: down %d\n", urb->status);
+ break;
+ default:
+ dev_err(dev, "NEEP: unknown status %d\n", urb->status);
+ break;
+ }
+ i1480->evt_result = urb->actual_length;
+ complete(&i1480->evt_complete);
+ return;
+}
+
+
+/**
+ * Wait for the MAC FW to initialize
+ *
+ * MAC FW sends a 0xfd/0101/00 notification to EP1 when done
+ * initializing. Get that notification into i1480->evt_buf; upper layer
+ * will verify it.
+ *
+ * Set i1480->evt_result with the result of getting the event or its
+ * size (if successful).
+ *
+ * Delivers the data directly to i1480->evt_buf
+ */
+static
+int i1480_usb_wait_init_done(struct i1480 *i1480)
+{
+ int result;
+ struct device *dev = i1480->dev;
+ struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+ struct usb_endpoint_descriptor *epd;
+
+ init_completion(&i1480->evt_complete);
+ i1480->evt_result = -EINPROGRESS;
+ epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(i1480_usb->neep_urb, i1480_usb->usb_dev,
+ usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
+ i1480->evt_buf, i1480->buf_size,
+ i1480_usb_neep_cb, i1480, epd->bInterval);
+ result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "init done: cannot submit NEEP read: %d\n",
+ result);
+ goto error_submit;
+ }
+ /* Wait for the USB callback to get the data */
+ result = wait_for_completion_interruptible_timeout(
+ &i1480->evt_complete, HZ);
+ if (result <= 0) {
+ result = result == 0 ? -ETIMEDOUT : result;
+ goto error_wait;
+ }
+ usb_kill_urb(i1480_usb->neep_urb);
+ return 0;
+
+error_wait:
+ usb_kill_urb(i1480_usb->neep_urb);
+error_submit:
+ i1480->evt_result = result;
+ return result;
+}
+
+
+/**
+ * Generic function for issuing commands to the i1480
+ *
+ * @i1480: i1480 instance
+ * @cmd_name: Name of the command (for error messages)
+ * @cmd: Pointer to command buffer
+ * @cmd_size: Size of the command buffer
+ * @reply: Buffer for the reply event
+ * @reply_size: Expected size back (including RCEB); the reply buffer
+ * is assumed to be as big as this.
+ * @returns: >= 0 size of the returned event data if ok,
+ * < 0 errno code on error.
+ *
+ * Arms the NE handle, issues the command to the device and checks the
+ * basics of the reply event.
+ */
+static
+int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size)
+{
+ int result;
+ struct device *dev = i1480->dev;
+ struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+ struct usb_endpoint_descriptor *epd;
+ struct uwb_rccb *cmd = i1480->cmd_buf;
+ u8 iface_no;
+
+ /* Post a read on the notification & event endpoint */
+ iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(
+ i1480_usb->neep_urb, i1480_usb->usb_dev,
+ usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
+ i1480->evt_buf, i1480->buf_size,
+ i1480_usb_neep_cb, i1480, epd->bInterval);
+ result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "%s: cannot submit NEEP read: %d\n",
+ cmd_name, result);
+ goto error_submit_ep1;
+ }
+ /* Now post the command on EP0 */
+ result = usb_control_msg(
+ i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
+ WA_EXEC_RC_CMD,
+ USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+ 0, iface_no,
+ cmd, cmd_size,
+ 100 /* FIXME: this is totally arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "%s: control request failed: %d\n",
+ cmd_name, result);
+ goto error_submit_ep0;
+ }
+ return result;
+
+error_submit_ep0:
+ usb_kill_urb(i1480_usb->neep_urb);
+error_submit_ep1:
+ return result;
+}
+
+
+/*
+ * Probe a i1480 device for uploading firmware.
+ *
+ * We attach only to interface #0, which is the radio control interface.
+ */
+static
+int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(iface);
+ struct i1480_usb *i1480_usb;
+ struct i1480 *i1480;
+ struct device *dev = &iface->dev;
+ int result;
+
+ result = -ENODEV;
+ if (iface->cur_altsetting->desc.bInterfaceNumber != 0) {
+ dev_dbg(dev, "not attaching to iface %d\n",
+ iface->cur_altsetting->desc.bInterfaceNumber);
+ goto error;
+ }
+ if (iface->num_altsetting > 1 &&
+ le16_to_cpu(udev->descriptor.idProduct) == 0xbabe) {
+ /* Need altsetting #1 [HW QUIRK] or EP1 won't work */
+ result = usb_set_interface(interface_to_usbdev(iface), 0, 1);
+ if (result < 0)
+ dev_warn(dev,
+ "can't set altsetting 1 on iface 0: %d\n",
+ result);
+ }
+
+ if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
+ result = -ENOMEM;
+ i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
+ if (i1480_usb == NULL) {
+ dev_err(dev, "Unable to allocate instance\n");
+ goto error;
+ }
+ i1480_usb_init(i1480_usb);
+
+ i1480 = &i1480_usb->i1480;
+ i1480->buf_size = 512;
+ i1480->cmd_buf = kmalloc_array(2, i1480->buf_size, GFP_KERNEL);
+ if (i1480->cmd_buf == NULL) {
+ dev_err(dev, "Cannot allocate transfer buffers\n");
+ result = -ENOMEM;
+ goto error_buf_alloc;
+ }
+ i1480->evt_buf = i1480->cmd_buf + i1480->buf_size;
+
+ result = i1480_usb_create(i1480_usb, iface);
+ if (result < 0) {
+ dev_err(dev, "Cannot create instance: %d\n", result);
+ goto error_create;
+ }
+
+ /* setup the fops and upload the firmware */
+ i1480->pre_fw_name = "i1480-pre-phy-0.0.bin";
+ i1480->mac_fw_name = "i1480-usb-0.0.bin";
+ i1480->mac_fw_name_deprecate = "ptc-0.0.bin";
+ i1480->phy_fw_name = "i1480-phy-0.0.bin";
+ i1480->dev = &iface->dev;
+ i1480->write = i1480_usb_write;
+ i1480->read = i1480_usb_read;
+ i1480->rc_setup = NULL;
+ i1480->wait_init_done = i1480_usb_wait_init_done;
+ i1480->cmd = i1480_usb_cmd;
+
+ result = i1480_fw_upload(&i1480_usb->i1480); /* the real thing */
+ if (result >= 0) {
+ usb_reset_device(i1480_usb->usb_dev);
+ result = -ENODEV; /* we don't want to bind to the iface */
+ }
+ i1480_usb_destroy(i1480_usb);
+error_create:
+ kfree(i1480->cmd_buf);
+error_buf_alloc:
+ kfree(i1480_usb);
+error:
+ return result;
+}
+
+MODULE_FIRMWARE("i1480-pre-phy-0.0.bin");
+MODULE_FIRMWARE("i1480-usb-0.0.bin");
+MODULE_FIRMWARE("i1480-phy-0.0.bin");
+
+#define i1480_USB_DEV(v, p) \
+{ \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE \
+ | USB_DEVICE_ID_MATCH_DEV_INFO \
+ | USB_DEVICE_ID_MATCH_INT_INFO, \
+ .idVendor = (v), \
+ .idProduct = (p), \
+ .bDeviceClass = 0xff, \
+ .bDeviceSubClass = 0xff, \
+ .bDeviceProtocol = 0xff, \
+ .bInterfaceClass = 0xff, \
+ .bInterfaceSubClass = 0xff, \
+ .bInterfaceProtocol = 0xff, \
+}
+
+
+/** USB device ID's that we handle */
+static const struct usb_device_id i1480_usb_id_table[] = {
+ i1480_USB_DEV(0x8086, 0xdf3b),
+ i1480_USB_DEV(0x15a9, 0x0005),
+ i1480_USB_DEV(0x07d1, 0x3802),
+ i1480_USB_DEV(0x050d, 0x305a),
+ i1480_USB_DEV(0x3495, 0x3007),
+ {},
+};
+MODULE_DEVICE_TABLE(usb, i1480_usb_id_table);
+
+
+static struct usb_driver i1480_dfu_driver = {
+ .name = "i1480-dfu-usb",
+ .id_table = i1480_usb_id_table,
+ .probe = i1480_usb_probe,
+ .disconnect = NULL,
+};
+
+module_usb_driver(i1480_dfu_driver);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Intel Wireless UWB Link 1480 firmware uploader for USB");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/i1480/i1480-est.c b/drivers/staging/uwb/i1480/i1480-est.c
new file mode 100644
index 000000000000..106e0a44b138
--- /dev/null
+++ b/drivers/staging/uwb/i1480/i1480-est.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Wireless UWB Link 1480
+ * Event Size tables for Wired Adaptors
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "../uwb.h"
+#include "dfu/i1480-dfu.h"
+
+
+/** Event size table for wEvents 0x00XX */
+static struct uwb_est_entry i1480_est_fd00[] = {
+ /* Anybody expecting this response has to use
+ * neh->extra_size to specify the real size that will
+ * come back. */
+ [i1480_EVT_CONFIRM] = { .size = sizeof(struct i1480_evt_confirm) },
+ [i1480_CMD_SET_IP_MAS] = { .size = sizeof(struct i1480_evt_confirm) },
+#ifdef i1480_RCEB_EXTENDED
+ [0x09] = {
+ .size = sizeof(struct i1480_rceb),
+ .offset = 1 + offsetof(struct i1480_rceb, wParamLength),
+ },
+#endif
+};
+
+/** Event size table for wEvents 0x01XX */
+static struct uwb_est_entry i1480_est_fd01[] = {
+ [0xff & i1480_EVT_RM_INIT_DONE] = { .size = sizeof(struct i1480_rceb) },
+ [0xff & i1480_EVT_DEV_ADD] = { .size = sizeof(struct i1480_rceb) + 9 },
+ [0xff & i1480_EVT_DEV_RM] = { .size = sizeof(struct i1480_rceb) + 9 },
+ [0xff & i1480_EVT_DEV_ID_CHANGE] = {
+ .size = sizeof(struct i1480_rceb) + 2 },
+};
+
+static int __init i1480_est_init(void)
+{
+ int result = uwb_est_register(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
+ i1480_est_fd00,
+ ARRAY_SIZE(i1480_est_fd00));
+ if (result < 0) {
+ printk(KERN_ERR "Can't register EST table fd00: %d\n", result);
+ return result;
+ }
+ result = uwb_est_register(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b,
+ i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01));
+ if (result < 0) {
+ printk(KERN_ERR "Can't register EST table fd01: %d\n", result);
+ return result;
+ }
+ return 0;
+}
+module_init(i1480_est_init);
+
+static void __exit i1480_est_exit(void)
+{
+ uwb_est_unregister(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
+ i1480_est_fd00, ARRAY_SIZE(i1480_est_fd00));
+ uwb_est_unregister(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b,
+ i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01));
+}
+module_exit(i1480_est_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("i1480's Vendor Specific Event Size Tables");
+MODULE_LICENSE("GPL");
+
+/**
+ * USB device ID's that we handle
+ *
+ * [so we are loaded when this kind device is connected]
+ */
+static struct usb_device_id __used i1480_est_id_table[] = {
+ { USB_DEVICE(0x8086, 0xdf3b), },
+ { USB_DEVICE(0x8086, 0x0c3b), },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, i1480_est_id_table);
diff --git a/drivers/staging/uwb/ie-rcv.c b/drivers/staging/uwb/ie-rcv.c
new file mode 100644
index 000000000000..51a4706e0dd3
--- /dev/null
+++ b/drivers/staging/uwb/ie-rcv.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * IE Received notification handling.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/bitmap.h>
+#include "uwb-internal.h"
+
+/*
+ * Process an incoming IE Received notification.
+ */
+int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *evt)
+{
+ int result = -EINVAL;
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc_evt_ie_rcv *iercv;
+
+ /* Is there enough data to decode it? */
+ if (evt->notif.size < sizeof(*iercv)) {
+ dev_err(dev, "IE Received notification: Not enough data to "
+ "decode (%zu vs %zu bytes needed)\n",
+ evt->notif.size, sizeof(*iercv));
+ goto error;
+ }
+ iercv = container_of(evt->notif.rceb, struct uwb_rc_evt_ie_rcv, rceb);
+
+ dev_dbg(dev, "IE received, element ID=%d\n", iercv->IEData[0]);
+
+ if (iercv->IEData[0] == UWB_RELINQUISH_REQUEST_IE) {
+ dev_warn(dev, "unhandled Relinquish Request IE\n");
+ }
+
+ return 0;
+error:
+ return result;
+}
diff --git a/drivers/staging/uwb/ie.c b/drivers/staging/uwb/ie.c
new file mode 100644
index 000000000000..b11678dd0380
--- /dev/null
+++ b/drivers/staging/uwb/ie.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Information Element Handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Reinette Chatre <reinette.chatre@intel.com>
+ *
+ * FIXME: docs
+ */
+
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "uwb-internal.h"
+
+/**
+ * uwb_ie_next - get the next IE in a buffer
+ * @ptr: start of the buffer containing the IE data
+ * @len: length of the buffer
+ *
+ * Both @ptr and @len are updated so subsequent calls to uwb_ie_next()
+ * will get the next IE.
+ *
+ * NULL is returned (and @ptr and @len will not be updated) if there
+ * are no more IEs in the buffer or the buffer is too short.
+ */
+struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len)
+{
+ struct uwb_ie_hdr *hdr;
+ size_t ie_len;
+
+ if (*len < sizeof(struct uwb_ie_hdr))
+ return NULL;
+
+ hdr = *ptr;
+ ie_len = sizeof(struct uwb_ie_hdr) + hdr->length;
+
+ if (*len < ie_len)
+ return NULL;
+
+ *ptr += ie_len;
+ *len -= ie_len;
+
+ return hdr;
+}
+EXPORT_SYMBOL_GPL(uwb_ie_next);
+
+/**
+ * uwb_ie_dump_hex - print IEs to a character buffer
+ * @ies: the IEs to print.
+ * @len: length of all the IEs.
+ * @buf: the destination buffer.
+ * @size: size of @buf.
+ *
+ * Returns the number of characters written.
+ */
+int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len,
+ char *buf, size_t size)
+{
+ void *ptr;
+ const struct uwb_ie_hdr *ie;
+ int r = 0;
+ u8 *d;
+
+ ptr = (void *)ies;
+ for (;;) {
+ ie = uwb_ie_next(&ptr, &len);
+ if (!ie)
+ break;
+
+ r += scnprintf(buf + r, size - r, "%02x %02x",
+ (unsigned)ie->element_id,
+ (unsigned)ie->length);
+ d = (uint8_t *)ie + sizeof(struct uwb_ie_hdr);
+ while (d != ptr && r < size)
+ r += scnprintf(buf + r, size - r, " %02x", (unsigned)*d++);
+ if (r < size)
+ buf[r++] = '\n';
+ };
+
+ return r;
+}
+
+/**
+ * Get the IEs that a radio controller is sending in its beacon
+ *
+ * @uwb_rc: UWB Radio Controller
+ * @returns: Size read from the system
+ *
+ * We don't need to lock the uwb_rc's mutex because we don't modify
+ * anything. Once done with the iedata buffer, call
+ * uwb_rc_ie_release(iedata). Don't call kfree on it.
+ */
+static
+ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie)
+{
+ ssize_t result;
+ struct device *dev = &uwb_rc->uwb_dev.dev;
+ struct uwb_rccb *cmd = NULL;
+ struct uwb_rceb *reply = NULL;
+ struct uwb_rc_evt_get_ie *get_ie;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->bCommandType = UWB_RC_CET_GENERAL;
+ cmd->wCommand = cpu_to_le16(UWB_RC_CMD_GET_IE);
+ result = uwb_rc_vcmd(uwb_rc, "GET_IE", cmd, sizeof(*cmd),
+ UWB_RC_CET_GENERAL, UWB_RC_CMD_GET_IE,
+ &reply);
+ kfree(cmd);
+ if (result < 0)
+ return result;
+
+ get_ie = container_of(reply, struct uwb_rc_evt_get_ie, rceb);
+ if (result < sizeof(*get_ie)) {
+ dev_err(dev, "not enough data returned for decoding GET IE "
+ "(%zu bytes received vs %zu needed)\n",
+ result, sizeof(*get_ie));
+ return -EINVAL;
+ } else if (result < sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)) {
+ dev_err(dev, "not enough data returned for decoding GET IE "
+ "payload (%zu bytes received vs %zu needed)\n", result,
+ sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength));
+ return -EINVAL;
+ }
+
+ *pget_ie = get_ie;
+ return result;
+}
+
+
+/**
+ * Replace all IEs currently being transmitted by a device
+ *
+ * @cmd: pointer to the SET-IE command with the IEs to set
+ * @size: size of @buf
+ */
+int uwb_rc_set_ie(struct uwb_rc *rc, struct uwb_rc_cmd_set_ie *cmd)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_evt_set_ie reply;
+
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_SET_IE;
+ result = uwb_rc_cmd(rc, "SET-IE", &cmd->rccb,
+ sizeof(*cmd) + le16_to_cpu(cmd->wIELength),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ else if (result != sizeof(reply)) {
+ dev_err(dev, "SET-IE: not enough data to decode reply "
+ "(%d bytes received vs %zu needed)\n",
+ result, sizeof(reply));
+ result = -EIO;
+ } else if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(dev, "SET-IE: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ } else
+ result = 0;
+error_cmd:
+ return result;
+}
+
+/* Cleanup the whole IE management subsystem */
+void uwb_rc_ie_init(struct uwb_rc *uwb_rc)
+{
+ mutex_init(&uwb_rc->ies_mutex);
+}
+
+
+/**
+ * uwb_rc_ie_setup - setup a radio controller's IE manager
+ * @uwb_rc: the radio controller.
+ *
+ * The current set of IEs are obtained from the hardware with a GET-IE
+ * command (since the radio controller is not yet beaconing this will
+ * be just the hardware's MAC and PHY Capability IEs).
+ *
+ * Returns 0 on success; -ve on an error.
+ */
+int uwb_rc_ie_setup(struct uwb_rc *uwb_rc)
+{
+ struct uwb_rc_evt_get_ie *ie_info = NULL;
+ int capacity;
+
+ capacity = uwb_rc_get_ie(uwb_rc, &ie_info);
+ if (capacity < 0)
+ return capacity;
+
+ mutex_lock(&uwb_rc->ies_mutex);
+
+ uwb_rc->ies = (struct uwb_rc_cmd_set_ie *)ie_info;
+ uwb_rc->ies->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ uwb_rc->ies->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_IE);
+ uwb_rc->ies_capacity = capacity;
+
+ mutex_unlock(&uwb_rc->ies_mutex);
+
+ return 0;
+}
+
+
+/* Cleanup the whole IE management subsystem */
+void uwb_rc_ie_release(struct uwb_rc *uwb_rc)
+{
+ kfree(uwb_rc->ies);
+ uwb_rc->ies = NULL;
+ uwb_rc->ies_capacity = 0;
+}
+
+
+static int uwb_rc_ie_add_one(struct uwb_rc *rc, const struct uwb_ie_hdr *new_ie)
+{
+ struct uwb_rc_cmd_set_ie *new_ies;
+ void *ptr, *prev_ie;
+ struct uwb_ie_hdr *ie;
+ size_t length, new_ie_len, new_capacity, size, prev_size;
+
+ length = le16_to_cpu(rc->ies->wIELength);
+ new_ie_len = sizeof(struct uwb_ie_hdr) + new_ie->length;
+ new_capacity = sizeof(struct uwb_rc_cmd_set_ie) + length + new_ie_len;
+
+ if (new_capacity > rc->ies_capacity) {
+ new_ies = krealloc(rc->ies, new_capacity, GFP_KERNEL);
+ if (!new_ies)
+ return -ENOMEM;
+ rc->ies = new_ies;
+ }
+
+ ptr = rc->ies->IEData;
+ size = length;
+ for (;;) {
+ prev_ie = ptr;
+ prev_size = size;
+ ie = uwb_ie_next(&ptr, &size);
+ if (!ie || ie->element_id > new_ie->element_id)
+ break;
+ }
+
+ memmove(prev_ie + new_ie_len, prev_ie, prev_size);
+ memcpy(prev_ie, new_ie, new_ie_len);
+ rc->ies->wIELength = cpu_to_le16(length + new_ie_len);
+
+ return 0;
+}
+
+/**
+ * uwb_rc_ie_add - add new IEs to the radio controller's beacon
+ * @uwb_rc: the radio controller.
+ * @ies: the buffer containing the new IE or IEs to be added to
+ * the device's beacon.
+ * @size: length of all the IEs.
+ *
+ * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
+ * after the device sent the first beacon that includes the IEs specified
+ * in the SET IE command. We thus cannot send this command if the device is
+ * not beaconing. Instead, a SET IE command will be sent later right after
+ * we start beaconing.
+ *
+ * Setting an IE on the device will overwrite all current IEs in device. So
+ * we take the current IEs being transmitted by the device, insert the
+ * new one, and call SET IE with all the IEs needed.
+ *
+ * Returns 0 on success; or -ENOMEM.
+ */
+int uwb_rc_ie_add(struct uwb_rc *uwb_rc,
+ const struct uwb_ie_hdr *ies, size_t size)
+{
+ int result = 0;
+ void *ptr;
+ const struct uwb_ie_hdr *ie;
+
+ mutex_lock(&uwb_rc->ies_mutex);
+
+ ptr = (void *)ies;
+ for (;;) {
+ ie = uwb_ie_next(&ptr, &size);
+ if (!ie)
+ break;
+
+ result = uwb_rc_ie_add_one(uwb_rc, ie);
+ if (result < 0)
+ break;
+ }
+ if (result >= 0) {
+ if (size == 0) {
+ if (uwb_rc->beaconing != -1)
+ result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
+ } else
+ result = -EINVAL;
+ }
+
+ mutex_unlock(&uwb_rc->ies_mutex);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_ie_add);
+
+
+/*
+ * Remove an IE from internal cache
+ *
+ * We are dealing with our internal IE cache so no need to verify that the
+ * IEs are valid (it has been done already).
+ *
+ * Should be called with ies_mutex held
+ *
+ * We do not break out once an IE is found in the cache. It is currently
+ * possible to have more than one IE with the same ID included in the
+ * beacon. We don't reallocate, we just mark the size smaller.
+ */
+static
+void uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove)
+{
+ struct uwb_ie_hdr *ie;
+ size_t len = le16_to_cpu(uwb_rc->ies->wIELength);
+ void *ptr;
+ size_t size;
+
+ ptr = uwb_rc->ies->IEData;
+ size = len;
+ for (;;) {
+ ie = uwb_ie_next(&ptr, &size);
+ if (!ie)
+ break;
+ if (ie->element_id == to_remove) {
+ len -= sizeof(struct uwb_ie_hdr) + ie->length;
+ memmove(ie, ptr, size);
+ ptr = ie;
+ }
+ }
+ uwb_rc->ies->wIELength = cpu_to_le16(len);
+}
+
+
+/**
+ * uwb_rc_ie_rm - remove an IE from the radio controller's beacon
+ * @uwb_rc: the radio controller.
+ * @element_id: the element ID of the IE to remove.
+ *
+ * Only IEs previously added with uwb_rc_ie_add() may be removed.
+ *
+ * Returns 0 on success; or -ve the SET-IE command to the radio
+ * controller failed.
+ */
+int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id)
+{
+ int result = 0;
+
+ mutex_lock(&uwb_rc->ies_mutex);
+
+ uwb_rc_ie_cache_rm(uwb_rc, element_id);
+
+ if (uwb_rc->beaconing != -1)
+ result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
+
+ mutex_unlock(&uwb_rc->ies_mutex);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_ie_rm);
diff --git a/drivers/staging/uwb/include/debug-cmd.h b/drivers/staging/uwb/include/debug-cmd.h
new file mode 100644
index 000000000000..f97db6c3bcc0
--- /dev/null
+++ b/drivers/staging/uwb/include/debug-cmd.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Ultra Wide Band
+ * Debug interface commands
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#ifndef __LINUX__UWB__DEBUG_CMD_H__
+#define __LINUX__UWB__DEBUG_CMD_H__
+
+#include <linux/types.h>
+
+/*
+ * Debug interface commands
+ *
+ * UWB_DBG_CMD_RSV_ESTABLISH: Establish a new unicast reservation.
+ *
+ * UWB_DBG_CMD_RSV_TERMINATE: Terminate the Nth reservation.
+ */
+
+enum uwb_dbg_cmd_type {
+ UWB_DBG_CMD_RSV_ESTABLISH = 1,
+ UWB_DBG_CMD_RSV_TERMINATE = 2,
+ UWB_DBG_CMD_IE_ADD = 3,
+ UWB_DBG_CMD_IE_RM = 4,
+ UWB_DBG_CMD_RADIO_START = 5,
+ UWB_DBG_CMD_RADIO_STOP = 6,
+};
+
+struct uwb_dbg_cmd_rsv_establish {
+ __u8 target[6];
+ __u8 type;
+ __u16 max_mas;
+ __u16 min_mas;
+ __u8 max_interval;
+};
+
+struct uwb_dbg_cmd_rsv_terminate {
+ int index;
+};
+
+struct uwb_dbg_cmd_ie {
+ __u8 data[128];
+ int len;
+};
+
+struct uwb_dbg_cmd {
+ __u32 type;
+ union {
+ struct uwb_dbg_cmd_rsv_establish rsv_establish;
+ struct uwb_dbg_cmd_rsv_terminate rsv_terminate;
+ struct uwb_dbg_cmd_ie ie_add;
+ struct uwb_dbg_cmd_ie ie_rm;
+ };
+};
+
+#endif /* #ifndef __LINUX__UWB__DEBUG_CMD_H__ */
diff --git a/drivers/staging/uwb/include/spec.h b/drivers/staging/uwb/include/spec.h
new file mode 100644
index 000000000000..5f75caf7b4ba
--- /dev/null
+++ b/drivers/staging/uwb/include/spec.h
@@ -0,0 +1,767 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Ultra Wide Band
+ * UWB Standard definitions
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * All these definitions are based on the ECMA-368 standard.
+ *
+ * Note all definitions are Little Endian in the wire, and we will
+ * convert them to host order before operating on the bitfields (that
+ * yes, we use extensively).
+ */
+
+#ifndef __LINUX__UWB_SPEC_H__
+#define __LINUX__UWB_SPEC_H__
+
+#include <linux/types.h>
+#include <linux/bitmap.h>
+#include <linux/if_ether.h>
+
+#define i1480_FW 0x00000303
+/* #define i1480_FW 0x00000302 */
+
+/**
+ * Number of Medium Access Slots in a superframe.
+ *
+ * UWB divides time in SuperFrames, each one divided in 256 pieces, or
+ * Medium Access Slots. See MBOA MAC[5.4.5] for details. The MAS is the
+ * basic bandwidth allocation unit in UWB.
+ */
+enum { UWB_NUM_MAS = 256 };
+
+/**
+ * Number of Zones in superframe.
+ *
+ * UWB divides the superframe into zones with numbering starting from BPST.
+ * See MBOA MAC[16.8.6]
+ */
+enum { UWB_NUM_ZONES = 16 };
+
+/*
+ * Number of MAS in a zone.
+ */
+#define UWB_MAS_PER_ZONE (UWB_NUM_MAS / UWB_NUM_ZONES)
+
+/*
+ * Number of MAS required before a row can be considered available.
+ */
+#define UWB_USABLE_MAS_PER_ROW (UWB_NUM_ZONES - 1)
+
+/*
+ * Number of streams per DRP reservation between a pair of devices.
+ *
+ * [ECMA-368] section 16.8.6.
+ */
+enum { UWB_NUM_STREAMS = 8 };
+
+/*
+ * mMasLength
+ *
+ * The length of a MAS in microseconds.
+ *
+ * [ECMA-368] section 17.16.
+ */
+enum { UWB_MAS_LENGTH_US = 256 };
+
+/*
+ * mBeaconSlotLength
+ *
+ * The length of the beacon slot in microseconds.
+ *
+ * [ECMA-368] section 17.16
+ */
+enum { UWB_BEACON_SLOT_LENGTH_US = 85 };
+
+/*
+ * mMaxLostBeacons
+ *
+ * The number beacons missing in consecutive superframes before a
+ * device can be considered as unreachable.
+ *
+ * [ECMA-368] section 17.16
+ */
+enum { UWB_MAX_LOST_BEACONS = 3 };
+
+/*
+ * mDRPBackOffWinMin
+ *
+ * The minimum number of superframes to wait before trying to reserve
+ * extra MAS.
+ *
+ * [ECMA-368] section 17.16
+ */
+enum { UWB_DRP_BACKOFF_WIN_MIN = 2 };
+
+/*
+ * mDRPBackOffWinMax
+ *
+ * The maximum number of superframes to wait before trying to reserve
+ * extra MAS.
+ *
+ * [ECMA-368] section 17.16
+ */
+enum { UWB_DRP_BACKOFF_WIN_MAX = 16 };
+
+/*
+ * Length of a superframe in microseconds.
+ */
+#define UWB_SUPERFRAME_LENGTH_US (UWB_MAS_LENGTH_US * UWB_NUM_MAS)
+
+/**
+ * UWB MAC address
+ *
+ * It is *imperative* that this struct is exactly 6 packed bytes (as
+ * it is also used to define headers sent down and up the wire/radio).
+ */
+struct uwb_mac_addr {
+ u8 data[ETH_ALEN];
+} __attribute__((packed));
+
+
+/**
+ * UWB device address
+ *
+ * It is *imperative* that this struct is exactly 6 packed bytes (as
+ * it is also used to define headers sent down and up the wire/radio).
+ */
+struct uwb_dev_addr {
+ u8 data[2];
+} __attribute__((packed));
+
+
+/**
+ * Types of UWB addresses
+ *
+ * Order matters (by size).
+ */
+enum uwb_addr_type {
+ UWB_ADDR_DEV = 0,
+ UWB_ADDR_MAC = 1,
+};
+
+
+/** Size of a char buffer for printing a MAC/device address */
+enum { UWB_ADDR_STRSIZE = 32 };
+
+
+/** UWB WiMedia protocol IDs. */
+enum uwb_prid {
+ UWB_PRID_WLP_RESERVED = 0x0000,
+ UWB_PRID_WLP = 0x0001,
+ UWB_PRID_WUSB_BOT = 0x0010,
+ UWB_PRID_WUSB = 0x0010,
+ UWB_PRID_WUSB_TOP = 0x001F,
+};
+
+
+/** PHY Rate (MBOA MAC[7.8.12, Table 61]) */
+enum uwb_phy_rate {
+ UWB_PHY_RATE_53 = 0,
+ UWB_PHY_RATE_80,
+ UWB_PHY_RATE_106,
+ UWB_PHY_RATE_160,
+ UWB_PHY_RATE_200,
+ UWB_PHY_RATE_320,
+ UWB_PHY_RATE_400,
+ UWB_PHY_RATE_480,
+ UWB_PHY_RATE_INVALID
+};
+
+
+/**
+ * Different ways to scan (MBOA MAC[6.2.2, Table 8], WUSB[Table 8-78])
+ */
+enum uwb_scan_type {
+ UWB_SCAN_ONLY = 0,
+ UWB_SCAN_OUTSIDE_BP,
+ UWB_SCAN_WHILE_INACTIVE,
+ UWB_SCAN_DISABLED,
+ UWB_SCAN_ONLY_STARTTIME,
+ UWB_SCAN_TOP
+};
+
+
+/** ACK Policy types (MBOA MAC[7.2.1.3]) */
+enum uwb_ack_pol {
+ UWB_ACK_NO = 0,
+ UWB_ACK_INM = 1,
+ UWB_ACK_B = 2,
+ UWB_ACK_B_REQ = 3,
+};
+
+
+/** DRP reservation types ([ECMA-368 table 106) */
+enum uwb_drp_type {
+ UWB_DRP_TYPE_ALIEN_BP = 0,
+ UWB_DRP_TYPE_HARD,
+ UWB_DRP_TYPE_SOFT,
+ UWB_DRP_TYPE_PRIVATE,
+ UWB_DRP_TYPE_PCA,
+};
+
+
+/** DRP Reason Codes ([ECMA-368] table 107) */
+enum uwb_drp_reason {
+ UWB_DRP_REASON_ACCEPTED = 0,
+ UWB_DRP_REASON_CONFLICT,
+ UWB_DRP_REASON_PENDING,
+ UWB_DRP_REASON_DENIED,
+ UWB_DRP_REASON_MODIFIED,
+};
+
+/** Relinquish Request Reason Codes ([ECMA-368] table 113) */
+enum uwb_relinquish_req_reason {
+ UWB_RELINQUISH_REQ_REASON_NON_SPECIFIC = 0,
+ UWB_RELINQUISH_REQ_REASON_OVER_ALLOCATION,
+};
+
+/**
+ * DRP Notification Reason Codes (WHCI 0.95 [3.1.4.9])
+ */
+enum uwb_drp_notif_reason {
+ UWB_DRP_NOTIF_DRP_IE_RCVD = 0,
+ UWB_DRP_NOTIF_CONFLICT,
+ UWB_DRP_NOTIF_TERMINATE,
+};
+
+
+/** Allocation of MAS slots in a DRP request MBOA MAC[7.8.7] */
+struct uwb_drp_alloc {
+ __le16 zone_bm;
+ __le16 mas_bm;
+} __attribute__((packed));
+
+
+/** General MAC Header format (ECMA-368[16.2]) */
+struct uwb_mac_frame_hdr {
+ __le16 Frame_Control;
+ struct uwb_dev_addr DestAddr;
+ struct uwb_dev_addr SrcAddr;
+ __le16 Sequence_Control;
+ __le16 Access_Information;
+} __attribute__((packed));
+
+
+/**
+ * uwb_beacon_frame - a beacon frame including MAC headers
+ *
+ * [ECMA] section 16.3.
+ */
+struct uwb_beacon_frame {
+ struct uwb_mac_frame_hdr hdr;
+ struct uwb_mac_addr Device_Identifier; /* may be a NULL EUI-48 */
+ u8 Beacon_Slot_Number;
+ u8 Device_Control;
+ u8 IEData[];
+} __attribute__((packed));
+
+
+/** Information Element codes (MBOA MAC[T54]) */
+enum uwb_ie {
+ UWB_PCA_AVAILABILITY = 2,
+ UWB_IE_DRP_AVAILABILITY = 8,
+ UWB_IE_DRP = 9,
+ UWB_BP_SWITCH_IE = 11,
+ UWB_MAC_CAPABILITIES_IE = 12,
+ UWB_PHY_CAPABILITIES_IE = 13,
+ UWB_APP_SPEC_PROBE_IE = 15,
+ UWB_IDENTIFICATION_IE = 19,
+ UWB_MASTER_KEY_ID_IE = 20,
+ UWB_RELINQUISH_REQUEST_IE = 21,
+ UWB_IE_WLP = 250, /* WiMedia Logical Link Control Protocol WLP 0.99 */
+ UWB_APP_SPEC_IE = 255,
+};
+
+
+/**
+ * Header common to all Information Elements (IEs)
+ */
+struct uwb_ie_hdr {
+ u8 element_id; /* enum uwb_ie */
+ u8 length;
+} __attribute__((packed));
+
+
+/** Dynamic Reservation Protocol IE (MBOA MAC[7.8.6]) */
+struct uwb_ie_drp {
+ struct uwb_ie_hdr hdr;
+ __le16 drp_control;
+ struct uwb_dev_addr dev_addr;
+ struct uwb_drp_alloc allocs[];
+} __attribute__((packed));
+
+static inline int uwb_ie_drp_type(struct uwb_ie_drp *ie)
+{
+ return (le16_to_cpu(ie->drp_control) >> 0) & 0x7;
+}
+
+static inline int uwb_ie_drp_stream_index(struct uwb_ie_drp *ie)
+{
+ return (le16_to_cpu(ie->drp_control) >> 3) & 0x7;
+}
+
+static inline int uwb_ie_drp_reason_code(struct uwb_ie_drp *ie)
+{
+ return (le16_to_cpu(ie->drp_control) >> 6) & 0x7;
+}
+
+static inline int uwb_ie_drp_status(struct uwb_ie_drp *ie)
+{
+ return (le16_to_cpu(ie->drp_control) >> 9) & 0x1;
+}
+
+static inline int uwb_ie_drp_owner(struct uwb_ie_drp *ie)
+{
+ return (le16_to_cpu(ie->drp_control) >> 10) & 0x1;
+}
+
+static inline int uwb_ie_drp_tiebreaker(struct uwb_ie_drp *ie)
+{
+ return (le16_to_cpu(ie->drp_control) >> 11) & 0x1;
+}
+
+static inline int uwb_ie_drp_unsafe(struct uwb_ie_drp *ie)
+{
+ return (le16_to_cpu(ie->drp_control) >> 12) & 0x1;
+}
+
+static inline void uwb_ie_drp_set_type(struct uwb_ie_drp *ie, enum uwb_drp_type type)
+{
+ u16 drp_control = le16_to_cpu(ie->drp_control);
+ drp_control = (drp_control & ~(0x7 << 0)) | (type << 0);
+ ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_stream_index(struct uwb_ie_drp *ie, int stream_index)
+{
+ u16 drp_control = le16_to_cpu(ie->drp_control);
+ drp_control = (drp_control & ~(0x7 << 3)) | (stream_index << 3);
+ ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_reason_code(struct uwb_ie_drp *ie,
+ enum uwb_drp_reason reason_code)
+{
+ u16 drp_control = le16_to_cpu(ie->drp_control);
+ drp_control = (ie->drp_control & ~(0x7 << 6)) | (reason_code << 6);
+ ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_status(struct uwb_ie_drp *ie, int status)
+{
+ u16 drp_control = le16_to_cpu(ie->drp_control);
+ drp_control = (drp_control & ~(0x1 << 9)) | (status << 9);
+ ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_owner(struct uwb_ie_drp *ie, int owner)
+{
+ u16 drp_control = le16_to_cpu(ie->drp_control);
+ drp_control = (drp_control & ~(0x1 << 10)) | (owner << 10);
+ ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_tiebreaker(struct uwb_ie_drp *ie, int tiebreaker)
+{
+ u16 drp_control = le16_to_cpu(ie->drp_control);
+ drp_control = (drp_control & ~(0x1 << 11)) | (tiebreaker << 11);
+ ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_unsafe(struct uwb_ie_drp *ie, int unsafe)
+{
+ u16 drp_control = le16_to_cpu(ie->drp_control);
+ drp_control = (drp_control & ~(0x1 << 12)) | (unsafe << 12);
+ ie->drp_control = cpu_to_le16(drp_control);
+}
+
+/** Dynamic Reservation Protocol IE (MBOA MAC[7.8.7]) */
+struct uwb_ie_drp_avail {
+ struct uwb_ie_hdr hdr;
+ DECLARE_BITMAP(bmp, UWB_NUM_MAS);
+} __attribute__((packed));
+
+/* Relinqish Request IE ([ECMA-368] section 16.8.19). */
+struct uwb_relinquish_request_ie {
+ struct uwb_ie_hdr hdr;
+ __le16 relinquish_req_control;
+ struct uwb_dev_addr dev_addr;
+ struct uwb_drp_alloc allocs[];
+} __attribute__((packed));
+
+static inline int uwb_ie_relinquish_req_reason_code(struct uwb_relinquish_request_ie *ie)
+{
+ return (le16_to_cpu(ie->relinquish_req_control) >> 0) & 0xf;
+}
+
+static inline void uwb_ie_relinquish_req_set_reason_code(struct uwb_relinquish_request_ie *ie,
+ int reason_code)
+{
+ u16 ctrl = le16_to_cpu(ie->relinquish_req_control);
+ ctrl = (ctrl & ~(0xf << 0)) | (reason_code << 0);
+ ie->relinquish_req_control = cpu_to_le16(ctrl);
+}
+
+/**
+ * The Vendor ID is set to an OUI that indicates the vendor of the device.
+ * ECMA-368 [16.8.10]
+ */
+struct uwb_vendor_id {
+ u8 data[3];
+} __attribute__((packed));
+
+/**
+ * The device type ID
+ * FIXME: clarify what this means
+ * ECMA-368 [16.8.10]
+ */
+struct uwb_device_type_id {
+ u8 data[3];
+} __attribute__((packed));
+
+
+/**
+ * UWB device information types
+ * ECMA-368 [16.8.10]
+ */
+enum uwb_dev_info_type {
+ UWB_DEV_INFO_VENDOR_ID = 0,
+ UWB_DEV_INFO_VENDOR_TYPE,
+ UWB_DEV_INFO_NAME,
+};
+
+/**
+ * UWB device information found in Identification IE
+ * ECMA-368 [16.8.10]
+ */
+struct uwb_dev_info {
+ u8 type; /* enum uwb_dev_info_type */
+ u8 length;
+ u8 data[];
+} __attribute__((packed));
+
+/**
+ * UWB Identification IE
+ * ECMA-368 [16.8.10]
+ */
+struct uwb_identification_ie {
+ struct uwb_ie_hdr hdr;
+ struct uwb_dev_info info[];
+} __attribute__((packed));
+
+/*
+ * UWB Radio Controller
+ *
+ * These definitions are common to the Radio Control layers as
+ * exported by the WUSB1.0 HWA and WHCI interfaces.
+ */
+
+/** Radio Control Command Block (WUSB1.0[Table 8-65] and WHCI 0.95) */
+struct uwb_rccb {
+ u8 bCommandType; /* enum hwa_cet */
+ __le16 wCommand; /* Command code */
+ u8 bCommandContext; /* Context ID */
+} __attribute__((packed));
+
+
+/** Radio Control Event Block (WUSB[table 8-66], WHCI 0.95) */
+struct uwb_rceb {
+ u8 bEventType; /* enum hwa_cet */
+ __le16 wEvent; /* Event code */
+ u8 bEventContext; /* Context ID */
+} __attribute__((packed));
+
+
+enum {
+ UWB_RC_CET_GENERAL = 0, /* General Command/Event type */
+ UWB_RC_CET_EX_TYPE_1 = 1, /* Extended Type 1 Command/Event type */
+};
+
+/* Commands to the radio controller */
+enum uwb_rc_cmd {
+ UWB_RC_CMD_CHANNEL_CHANGE = 16,
+ UWB_RC_CMD_DEV_ADDR_MGMT = 17, /* Device Address Management */
+ UWB_RC_CMD_GET_IE = 18, /* GET Information Elements */
+ UWB_RC_CMD_RESET = 19,
+ UWB_RC_CMD_SCAN = 20, /* Scan management */
+ UWB_RC_CMD_SET_BEACON_FILTER = 21,
+ UWB_RC_CMD_SET_DRP_IE = 22, /* Dynamic Reservation Protocol IEs */
+ UWB_RC_CMD_SET_IE = 23, /* Information Element management */
+ UWB_RC_CMD_SET_NOTIFICATION_FILTER = 24,
+ UWB_RC_CMD_SET_TX_POWER = 25,
+ UWB_RC_CMD_SLEEP = 26,
+ UWB_RC_CMD_START_BEACON = 27,
+ UWB_RC_CMD_STOP_BEACON = 28,
+ UWB_RC_CMD_BP_MERGE = 29,
+ UWB_RC_CMD_SEND_COMMAND_FRAME = 30,
+ UWB_RC_CMD_SET_ASIE_NOTIF = 31,
+};
+
+/* Notifications from the radio controller */
+enum uwb_rc_evt {
+ UWB_RC_EVT_IE_RCV = 0,
+ UWB_RC_EVT_BEACON = 1,
+ UWB_RC_EVT_BEACON_SIZE = 2,
+ UWB_RC_EVT_BPOIE_CHANGE = 3,
+ UWB_RC_EVT_BP_SLOT_CHANGE = 4,
+ UWB_RC_EVT_BP_SWITCH_IE_RCV = 5,
+ UWB_RC_EVT_DEV_ADDR_CONFLICT = 6,
+ UWB_RC_EVT_DRP_AVAIL = 7,
+ UWB_RC_EVT_DRP = 8,
+ UWB_RC_EVT_BP_SWITCH_STATUS = 9,
+ UWB_RC_EVT_CMD_FRAME_RCV = 10,
+ UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV = 11,
+ /* Events (command responses) use the same code as the command */
+ UWB_RC_EVT_UNKNOWN_CMD_RCV = 65535,
+};
+
+enum uwb_rc_extended_type_1_cmd {
+ UWB_RC_SET_DAA_ENERGY_MASK = 32,
+ UWB_RC_SET_NOTIFICATION_FILTER_EX = 33,
+};
+
+enum uwb_rc_extended_type_1_evt {
+ UWB_RC_DAA_ENERGY_DETECTED = 0,
+};
+
+/* Radio Control Result Code. [WHCI] table 3-3. */
+enum {
+ UWB_RC_RES_SUCCESS = 0,
+ UWB_RC_RES_FAIL,
+ UWB_RC_RES_FAIL_HARDWARE,
+ UWB_RC_RES_FAIL_NO_SLOTS,
+ UWB_RC_RES_FAIL_BEACON_TOO_LARGE,
+ UWB_RC_RES_FAIL_INVALID_PARAMETER,
+ UWB_RC_RES_FAIL_UNSUPPORTED_PWR_LEVEL,
+ UWB_RC_RES_FAIL_INVALID_IE_DATA,
+ UWB_RC_RES_FAIL_BEACON_SIZE_EXCEEDED,
+ UWB_RC_RES_FAIL_CANCELLED,
+ UWB_RC_RES_FAIL_INVALID_STATE,
+ UWB_RC_RES_FAIL_INVALID_SIZE,
+ UWB_RC_RES_FAIL_ACK_NOT_RECEIVED,
+ UWB_RC_RES_FAIL_NO_MORE_ASIE_NOTIF,
+ UWB_RC_RES_FAIL_TIME_OUT = 255,
+};
+
+/* Confirm event. [WHCI] section 3.1.3.1 etc. */
+struct uwb_rc_evt_confirm {
+ struct uwb_rceb rceb;
+ u8 bResultCode;
+} __attribute__((packed));
+
+/* Device Address Management event. [WHCI] section 3.1.3.2. */
+struct uwb_rc_evt_dev_addr_mgmt {
+ struct uwb_rceb rceb;
+ u8 baAddr[ETH_ALEN];
+ u8 bResultCode;
+} __attribute__((packed));
+
+
+/* Get IE Event. [WHCI] section 3.1.3.3. */
+struct uwb_rc_evt_get_ie {
+ struct uwb_rceb rceb;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/* Set DRP IE Event. [WHCI] section 3.1.3.7. */
+struct uwb_rc_evt_set_drp_ie {
+ struct uwb_rceb rceb;
+ __le16 wRemainingSpace;
+ u8 bResultCode;
+} __attribute__((packed));
+
+/* Set IE Event. [WHCI] section 3.1.3.8. */
+struct uwb_rc_evt_set_ie {
+ struct uwb_rceb rceb;
+ __le16 RemainingSpace;
+ u8 bResultCode;
+} __attribute__((packed));
+
+/* Scan command. [WHCI] 3.1.3.5. */
+struct uwb_rc_cmd_scan {
+ struct uwb_rccb rccb;
+ u8 bChannelNumber;
+ u8 bScanState;
+ __le16 wStartTime;
+} __attribute__((packed));
+
+/* Set DRP IE command. [WHCI] section 3.1.3.7. */
+struct uwb_rc_cmd_set_drp_ie {
+ struct uwb_rccb rccb;
+ __le16 wIELength;
+ struct uwb_ie_drp IEData[];
+} __attribute__((packed));
+
+/* Set IE command. [WHCI] section 3.1.3.8. */
+struct uwb_rc_cmd_set_ie {
+ struct uwb_rccb rccb;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/* Set DAA Energy Mask event. [WHCI 0.96] section 3.1.3.17. */
+struct uwb_rc_evt_set_daa_energy_mask {
+ struct uwb_rceb rceb;
+ __le16 wLength;
+ u8 result;
+} __attribute__((packed));
+
+/* Set Notification Filter Extended event. [WHCI 0.96] section 3.1.3.18. */
+struct uwb_rc_evt_set_notification_filter_ex {
+ struct uwb_rceb rceb;
+ __le16 wLength;
+ u8 result;
+} __attribute__((packed));
+
+/* IE Received notification. [WHCI] section 3.1.4.1. */
+struct uwb_rc_evt_ie_rcv {
+ struct uwb_rceb rceb;
+ struct uwb_dev_addr SrcAddr;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/* Type of the received beacon. [WHCI] section 3.1.4.2. */
+enum uwb_rc_beacon_type {
+ UWB_RC_BEACON_TYPE_SCAN = 0,
+ UWB_RC_BEACON_TYPE_NEIGHBOR,
+ UWB_RC_BEACON_TYPE_OL_ALIEN,
+ UWB_RC_BEACON_TYPE_NOL_ALIEN,
+};
+
+/* Beacon received notification. [WHCI] 3.1.4.2. */
+struct uwb_rc_evt_beacon {
+ struct uwb_rceb rceb;
+ u8 bChannelNumber;
+ u8 bBeaconType;
+ __le16 wBPSTOffset;
+ u8 bLQI;
+ u8 bRSSI;
+ __le16 wBeaconInfoLength;
+ u8 BeaconInfo[];
+} __attribute__((packed));
+
+
+/* Beacon Size Change notification. [WHCI] section 3.1.4.3 */
+struct uwb_rc_evt_beacon_size {
+ struct uwb_rceb rceb;
+ __le16 wNewBeaconSize;
+} __attribute__((packed));
+
+
+/* BPOIE Change notification. [WHCI] section 3.1.4.4. */
+struct uwb_rc_evt_bpoie_change {
+ struct uwb_rceb rceb;
+ __le16 wBPOIELength;
+ u8 BPOIE[];
+} __attribute__((packed));
+
+
+/* Beacon Slot Change notification. [WHCI] section 3.1.4.5. */
+struct uwb_rc_evt_bp_slot_change {
+ struct uwb_rceb rceb;
+ u8 slot_info;
+} __attribute__((packed));
+
+static inline int uwb_rc_evt_bp_slot_change_slot_num(
+ const struct uwb_rc_evt_bp_slot_change *evt)
+{
+ return evt->slot_info & 0x7f;
+}
+
+static inline int uwb_rc_evt_bp_slot_change_no_slot(
+ const struct uwb_rc_evt_bp_slot_change *evt)
+{
+ return (evt->slot_info & 0x80) >> 7;
+}
+
+/* BP Switch IE Received notification. [WHCI] section 3.1.4.6. */
+struct uwb_rc_evt_bp_switch_ie_rcv {
+ struct uwb_rceb rceb;
+ struct uwb_dev_addr wSrcAddr;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/* DevAddr Conflict notification. [WHCI] section 3.1.4.7. */
+struct uwb_rc_evt_dev_addr_conflict {
+ struct uwb_rceb rceb;
+} __attribute__((packed));
+
+/* DRP notification. [WHCI] section 3.1.4.9. */
+struct uwb_rc_evt_drp {
+ struct uwb_rceb rceb;
+ struct uwb_dev_addr src_addr;
+ u8 reason;
+ u8 beacon_slot_number;
+ __le16 ie_length;
+ u8 ie_data[];
+} __attribute__((packed));
+
+static inline enum uwb_drp_notif_reason uwb_rc_evt_drp_reason(struct uwb_rc_evt_drp *evt)
+{
+ return evt->reason & 0x0f;
+}
+
+
+/* DRP Availability Change notification. [WHCI] section 3.1.4.8. */
+struct uwb_rc_evt_drp_avail {
+ struct uwb_rceb rceb;
+ DECLARE_BITMAP(bmp, UWB_NUM_MAS);
+} __attribute__((packed));
+
+/* BP switch status notification. [WHCI] section 3.1.4.10. */
+struct uwb_rc_evt_bp_switch_status {
+ struct uwb_rceb rceb;
+ u8 status;
+ u8 slot_offset;
+ __le16 bpst_offset;
+ u8 move_countdown;
+} __attribute__((packed));
+
+/* Command Frame Received notification. [WHCI] section 3.1.4.11. */
+struct uwb_rc_evt_cmd_frame_rcv {
+ struct uwb_rceb rceb;
+ __le16 receive_time;
+ struct uwb_dev_addr wSrcAddr;
+ struct uwb_dev_addr wDstAddr;
+ __le16 control;
+ __le16 reserved;
+ __le16 dataLength;
+ u8 data[];
+} __attribute__((packed));
+
+/* Channel Change IE Received notification. [WHCI] section 3.1.4.12. */
+struct uwb_rc_evt_channel_change_ie_rcv {
+ struct uwb_rceb rceb;
+ struct uwb_dev_addr wSrcAddr;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/* DAA Energy Detected notification. [WHCI 0.96] section 3.1.4.14. */
+struct uwb_rc_evt_daa_energy_detected {
+ struct uwb_rceb rceb;
+ __le16 wLength;
+ u8 bandID;
+ u8 reserved;
+ u8 toneBmp[16];
+} __attribute__((packed));
+
+
+/**
+ * Radio Control Interface Class Descriptor
+ *
+ * WUSB 1.0 [8.6.1.2]
+ */
+struct uwb_rc_control_intf_class_desc {
+ u8 bLength;
+ u8 bDescriptorType;
+ __le16 bcdRCIVersion;
+} __attribute__((packed));
+
+#endif /* #ifndef __LINUX__UWB_SPEC_H__ */
diff --git a/drivers/staging/uwb/include/umc.h b/drivers/staging/uwb/include/umc.h
new file mode 100644
index 000000000000..ddbceb39ad15
--- /dev/null
+++ b/drivers/staging/uwb/include/umc.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * UWB Multi-interface Controller support.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * UMC (UWB Multi-interface Controller) capabilities (e.g., radio
+ * controller, host controller) are presented as devices on the "umc"
+ * bus.
+ *
+ * The radio controller is not strictly a UMC capability but it's
+ * useful to present it as such.
+ *
+ * References:
+ *
+ * [WHCI] Wireless Host Controller Interface Specification for
+ * Certified Wireless Universal Serial Bus, revision 0.95.
+ *
+ * How this works is kind of convoluted but simple. The whci.ko driver
+ * loads when WHCI devices are detected. These WHCI devices expose
+ * many devices in the same PCI function (they couldn't have reused
+ * functions, no), so for each PCI function that exposes these many
+ * devices, whci ceates a umc_dev [whci_probe() -> whci_add_cap()]
+ * with umc_device_create() and adds it to the bus with
+ * umc_device_register().
+ *
+ * umc_device_register() calls device_register() which will push the
+ * bus management code to load your UMC driver's somehting_probe()
+ * that you have registered for that capability code.
+ *
+ * Now when the WHCI device is removed, whci_remove() will go over
+ * each umc_dev assigned to each of the PCI function's capabilities
+ * and through whci_del_cap() call umc_device_unregister() each
+ * created umc_dev. Of course, if you are bound to the device, your
+ * driver's something_remove() will be called.
+ */
+
+#ifndef _LINUX_UWB_UMC_H_
+#define _LINUX_UWB_UMC_H_
+
+#include <linux/device.h>
+#include <linux/pci.h>
+
+/*
+ * UMC capability IDs.
+ *
+ * 0x00 is reserved so use it for the radio controller device.
+ *
+ * [WHCI] table 2-8
+ */
+#define UMC_CAP_ID_WHCI_RC 0x00 /* radio controller */
+#define UMC_CAP_ID_WHCI_WUSB_HC 0x01 /* WUSB host controller */
+
+/**
+ * struct umc_dev - UMC capability device
+ *
+ * @version: version of the specification this capability conforms to.
+ * @cap_id: capability ID.
+ * @bar: PCI Bar (64 bit) where the resource lies
+ * @resource: register space resource.
+ * @irq: interrupt line.
+ */
+struct umc_dev {
+ u16 version;
+ u8 cap_id;
+ u8 bar;
+ struct resource resource;
+ unsigned irq;
+ struct device dev;
+};
+
+#define to_umc_dev(d) container_of(d, struct umc_dev, dev)
+
+/**
+ * struct umc_driver - UMC capability driver
+ * @cap_id: supported capability ID.
+ * @match: driver specific capability matching function.
+ * @match_data: driver specific data for match() (e.g., a
+ * table of pci_device_id's if umc_match_pci_id() is used).
+ */
+struct umc_driver {
+ char *name;
+ u8 cap_id;
+ int (*match)(struct umc_driver *, struct umc_dev *);
+ const void *match_data;
+
+ int (*probe)(struct umc_dev *);
+ void (*remove)(struct umc_dev *);
+ int (*pre_reset)(struct umc_dev *);
+ int (*post_reset)(struct umc_dev *);
+
+ struct device_driver driver;
+};
+
+#define to_umc_driver(d) container_of(d, struct umc_driver, driver)
+
+extern struct bus_type umc_bus_type;
+
+struct umc_dev *umc_device_create(struct device *parent, int n);
+int __must_check umc_device_register(struct umc_dev *umc);
+void umc_device_unregister(struct umc_dev *umc);
+
+int __must_check __umc_driver_register(struct umc_driver *umc_drv,
+ struct module *mod,
+ const char *mod_name);
+
+/**
+ * umc_driver_register - register a UMC capabiltity driver.
+ * @umc_drv: pointer to the driver.
+ */
+#define umc_driver_register(umc_drv) \
+ __umc_driver_register(umc_drv, THIS_MODULE, KBUILD_MODNAME)
+
+void umc_driver_unregister(struct umc_driver *umc_drv);
+
+/*
+ * Utility function you can use to match (umc_driver->match) against a
+ * null-terminated array of 'struct pci_device_id' in
+ * umc_driver->match_data.
+ */
+int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc);
+
+/**
+ * umc_parent_pci_dev - return the UMC's parent PCI device or NULL if none
+ * @umc_dev: UMC device whose parent PCI device we are looking for
+ *
+ * DIRTY!!! DON'T RELY ON THIS
+ *
+ * FIXME: This is as dirty as it gets, but we need some way to check
+ * the correct type of umc_dev->parent (so that for example, we can
+ * cast to pci_dev). Casting to pci_dev is necessary because at some
+ * point we need to request resources from the device. Mapping is
+ * easily over come (ioremap and stuff are bus agnostic), but hooking
+ * up to some error handlers (such as pci error handlers) might need
+ * this.
+ *
+ * THIS might (probably will) be removed in the future, so don't count
+ * on it.
+ */
+static inline struct pci_dev *umc_parent_pci_dev(struct umc_dev *umc_dev)
+{
+ struct pci_dev *pci_dev = NULL;
+ if (dev_is_pci(umc_dev->dev.parent))
+ pci_dev = to_pci_dev(umc_dev->dev.parent);
+ return pci_dev;
+}
+
+/**
+ * umc_dev_get() - reference a UMC device.
+ * @umc_dev: Pointer to UMC device.
+ *
+ * NOTE: we are assuming in this whole scheme that the parent device
+ * is referenced at _probe() time and unreferenced at _remove()
+ * time by the parent's subsystem.
+ */
+static inline struct umc_dev *umc_dev_get(struct umc_dev *umc_dev)
+{
+ get_device(&umc_dev->dev);
+ return umc_dev;
+}
+
+/**
+ * umc_dev_put() - unreference a UMC device.
+ * @umc_dev: Pointer to UMC device.
+ */
+static inline void umc_dev_put(struct umc_dev *umc_dev)
+{
+ put_device(&umc_dev->dev);
+}
+
+/**
+ * umc_set_drvdata - set UMC device's driver data.
+ * @umc_dev: Pointer to UMC device.
+ * @data: Data to set.
+ */
+static inline void umc_set_drvdata(struct umc_dev *umc_dev, void *data)
+{
+ dev_set_drvdata(&umc_dev->dev, data);
+}
+
+/**
+ * umc_get_drvdata - recover UMC device's driver data.
+ * @umc_dev: Pointer to UMC device.
+ */
+static inline void *umc_get_drvdata(struct umc_dev *umc_dev)
+{
+ return dev_get_drvdata(&umc_dev->dev);
+}
+
+int umc_controller_reset(struct umc_dev *umc);
+
+#endif /* #ifndef _LINUX_UWB_UMC_H_ */
diff --git a/drivers/staging/uwb/include/whci.h b/drivers/staging/uwb/include/whci.h
new file mode 100644
index 000000000000..1a5c2cc2b008
--- /dev/null
+++ b/drivers/staging/uwb/include/whci.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Wireless Host Controller Interface for Ultra-Wide-Band and Wireless USB
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * References:
+ * [WHCI] Wireless Host Controller Interface Specification for
+ * Certified Wireless Universal Serial Bus, revision 0.95.
+ */
+#ifndef _LINUX_UWB_WHCI_H_
+#define _LINUX_UWB_WHCI_H_
+
+#include <linux/pci.h>
+
+/*
+ * UWB interface capability registers (offsets from UWBBASE)
+ *
+ * [WHCI] section 2.2
+ */
+#define UWBCAPINFO 0x00 /* == UWBCAPDATA(0) */
+# define UWBCAPINFO_TO_N_CAPS(c) (((c) >> 0) & 0xFull)
+#define UWBCAPDATA(n) (8*(n))
+# define UWBCAPDATA_TO_VERSION(c) (((c) >> 32) & 0xFFFFull)
+# define UWBCAPDATA_TO_OFFSET(c) (((c) >> 18) & 0x3FFFull)
+# define UWBCAPDATA_TO_BAR(c) (((c) >> 16) & 0x3ull)
+# define UWBCAPDATA_TO_SIZE(c) ((((c) >> 8) & 0xFFull) * sizeof(u32))
+# define UWBCAPDATA_TO_CAP_ID(c) (((c) >> 0) & 0xFFull)
+
+/* Size of the WHCI capability data (including the RC capability) for
+ a device with n capabilities. */
+#define UWBCAPDATA_SIZE(n) (8 + 8*(n))
+
+
+/*
+ * URC registers (offsets from URCBASE)
+ *
+ * [WHCI] section 2.3
+ */
+#define URCCMD 0x00
+# define URCCMD_RESET (1 << 31) /* UMC Hardware reset */
+# define URCCMD_RS (1 << 30) /* Run/Stop */
+# define URCCMD_EARV (1 << 29) /* Event Address Register Valid */
+# define URCCMD_ACTIVE (1 << 15) /* Command is active */
+# define URCCMD_IWR (1 << 14) /* Interrupt When Ready */
+# define URCCMD_SIZE_MASK 0x00000fff /* Command size mask */
+#define URCSTS 0x04
+# define URCSTS_EPS (1 << 17) /* Event Processing Status */
+# define URCSTS_HALTED (1 << 16) /* RC halted */
+# define URCSTS_HSE (1 << 10) /* Host System Error...fried */
+# define URCSTS_ER (1 << 9) /* Event Ready */
+# define URCSTS_RCI (1 << 8) /* Ready for Command Interrupt */
+# define URCSTS_INT_MASK 0x00000700 /* URC interrupt sources */
+# define URCSTS_ISI 0x000000ff /* Interrupt Source Identification */
+#define URCINTR 0x08
+# define URCINTR_EN_ALL 0x000007ff /* Enable all interrupt sources */
+#define URCCMDADDR 0x10
+#define URCEVTADDR 0x18
+# define URCEVTADDR_OFFSET_MASK 0xfff /* Event pointer offset mask */
+
+
+/** Write 32 bit @value to little endian register at @addr */
+static inline
+void le_writel(u32 value, void __iomem *addr)
+{
+ iowrite32(value, addr);
+}
+
+
+/** Read from 32 bit little endian register at @addr */
+static inline
+u32 le_readl(void __iomem *addr)
+{
+ return ioread32(addr);
+}
+
+
+/** Write 64 bit @value to little endian register at @addr */
+static inline
+void le_writeq(u64 value, void __iomem *addr)
+{
+ iowrite32(value, addr);
+ iowrite32(value >> 32, addr + 4);
+}
+
+
+/** Read from 64 bit little endian register at @addr */
+static inline
+u64 le_readq(void __iomem *addr)
+{
+ u64 value;
+ value = ioread32(addr);
+ value |= (u64)ioread32(addr + 4) << 32;
+ return value;
+}
+
+extern int whci_wait_for(struct device *dev, u32 __iomem *reg,
+ u32 mask, u32 result,
+ unsigned long max_ms, const char *tag);
+
+#endif /* #ifndef _LINUX_UWB_WHCI_H_ */
diff --git a/drivers/staging/uwb/lc-dev.c b/drivers/staging/uwb/lc-dev.c
new file mode 100644
index 000000000000..3e5c07fd6b10
--- /dev/null
+++ b/drivers/staging/uwb/lc-dev.c
@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Life cycle of devices
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include "uwb-internal.h"
+
+/* We initialize addresses to 0xff (invalid, as it is bcast) */
+static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr)
+{
+ memset(&addr->data, 0xff, sizeof(addr->data));
+}
+
+static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr)
+{
+ memset(&addr->data, 0xff, sizeof(addr->data));
+}
+
+/*
+ * Add callback @new to be called when an event occurs in @rc.
+ */
+int uwb_notifs_register(struct uwb_rc *rc, struct uwb_notifs_handler *new)
+{
+ if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+ return -ERESTARTSYS;
+ list_add(&new->list_node, &rc->notifs_chain.list);
+ mutex_unlock(&rc->notifs_chain.mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_notifs_register);
+
+/*
+ * Remove event handler (callback)
+ */
+int uwb_notifs_deregister(struct uwb_rc *rc, struct uwb_notifs_handler *entry)
+{
+ if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+ return -ERESTARTSYS;
+ list_del(&entry->list_node);
+ mutex_unlock(&rc->notifs_chain.mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_notifs_deregister);
+
+/*
+ * Notify all event handlers of a given event on @rc
+ *
+ * We are called with a valid reference to the device, or NULL if the
+ * event is not for a particular event (e.g., a BG join event).
+ */
+void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event)
+{
+ struct uwb_notifs_handler *handler;
+ if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+ return;
+ if (!list_empty(&rc->notifs_chain.list)) {
+ list_for_each_entry(handler, &rc->notifs_chain.list, list_node) {
+ handler->cb(handler->data, uwb_dev, event);
+ }
+ }
+ mutex_unlock(&rc->notifs_chain.mutex);
+}
+
+/*
+ * Release the backing device of a uwb_dev that has been dynamically allocated.
+ */
+static void uwb_dev_sys_release(struct device *dev)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+ uwb_bce_put(uwb_dev->bce);
+ memset(uwb_dev, 0x69, sizeof(*uwb_dev));
+ kfree(uwb_dev);
+}
+
+/*
+ * Initialize a UWB device instance
+ *
+ * Alloc, zero and call this function.
+ */
+void uwb_dev_init(struct uwb_dev *uwb_dev)
+{
+ mutex_init(&uwb_dev->mutex);
+ device_initialize(&uwb_dev->dev);
+ uwb_dev->dev.release = uwb_dev_sys_release;
+ uwb_dev_addr_init(&uwb_dev->dev_addr);
+ uwb_mac_addr_init(&uwb_dev->mac_addr);
+ bitmap_fill(uwb_dev->streams, UWB_NUM_GLOBAL_STREAMS);
+}
+
+static ssize_t uwb_dev_EUI_48_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ char addr[UWB_ADDR_STRSIZE];
+
+ uwb_mac_addr_print(addr, sizeof(addr), &uwb_dev->mac_addr);
+ return sprintf(buf, "%s\n", addr);
+}
+static DEVICE_ATTR(EUI_48, S_IRUGO, uwb_dev_EUI_48_show, NULL);
+
+static ssize_t uwb_dev_DevAddr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ char addr[UWB_ADDR_STRSIZE];
+
+ uwb_dev_addr_print(addr, sizeof(addr), &uwb_dev->dev_addr);
+ return sprintf(buf, "%s\n", addr);
+}
+static DEVICE_ATTR(DevAddr, S_IRUGO, uwb_dev_DevAddr_show, NULL);
+
+/*
+ * Show the BPST of this device.
+ *
+ * Calculated from the receive time of the device's beacon and it's
+ * slot number.
+ */
+static ssize_t uwb_dev_BPST_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce;
+ struct uwb_beacon_frame *bf;
+ u16 bpst;
+
+ bce = uwb_dev->bce;
+ mutex_lock(&bce->mutex);
+ bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
+ bpst = bce->be->wBPSTOffset
+ - (u16)(bf->Beacon_Slot_Number * UWB_BEACON_SLOT_LENGTH_US);
+ mutex_unlock(&bce->mutex);
+
+ return sprintf(buf, "%d\n", bpst);
+}
+static DEVICE_ATTR(BPST, S_IRUGO, uwb_dev_BPST_show, NULL);
+
+/*
+ * Show the IEs a device is beaconing
+ *
+ * We need to access the beacon cache, so we just lock it really
+ * quick, print the IEs and unlock.
+ *
+ * We have a reference on the cache entry, so that should be
+ * quite safe.
+ */
+static ssize_t uwb_dev_IEs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+ return uwb_bce_print_IEs(uwb_dev, uwb_dev->bce, buf, PAGE_SIZE);
+}
+static DEVICE_ATTR(IEs, S_IRUGO | S_IWUSR, uwb_dev_IEs_show, NULL);
+
+static ssize_t uwb_dev_LQE_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce = uwb_dev->bce;
+ size_t result;
+
+ mutex_lock(&bce->mutex);
+ result = stats_show(&uwb_dev->bce->lqe_stats, buf);
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+
+static ssize_t uwb_dev_LQE_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce = uwb_dev->bce;
+ ssize_t result;
+
+ mutex_lock(&bce->mutex);
+ result = stats_store(&uwb_dev->bce->lqe_stats, buf, size);
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+static DEVICE_ATTR(LQE, S_IRUGO | S_IWUSR, uwb_dev_LQE_show, uwb_dev_LQE_store);
+
+static ssize_t uwb_dev_RSSI_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce = uwb_dev->bce;
+ size_t result;
+
+ mutex_lock(&bce->mutex);
+ result = stats_show(&uwb_dev->bce->rssi_stats, buf);
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+
+static ssize_t uwb_dev_RSSI_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce = uwb_dev->bce;
+ ssize_t result;
+
+ mutex_lock(&bce->mutex);
+ result = stats_store(&uwb_dev->bce->rssi_stats, buf, size);
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+static DEVICE_ATTR(RSSI, S_IRUGO | S_IWUSR, uwb_dev_RSSI_show, uwb_dev_RSSI_store);
+
+
+static struct attribute *uwb_dev_attrs[] = {
+ &dev_attr_EUI_48.attr,
+ &dev_attr_DevAddr.attr,
+ &dev_attr_BPST.attr,
+ &dev_attr_IEs.attr,
+ &dev_attr_LQE.attr,
+ &dev_attr_RSSI.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(uwb_dev);
+
+/* UWB bus type. */
+struct bus_type uwb_bus_type = {
+ .name = "uwb",
+ .dev_groups = uwb_dev_groups,
+};
+
+/**
+ * Device SYSFS registration
+ */
+static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev)
+{
+ struct device *dev;
+
+ dev = &uwb_dev->dev;
+ dev->parent = parent_dev;
+ dev_set_drvdata(dev, uwb_dev);
+
+ return device_add(dev);
+}
+
+
+static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev)
+{
+ dev_set_drvdata(&uwb_dev->dev, NULL);
+ device_del(&uwb_dev->dev);
+}
+
+
+/**
+ * Register and initialize a new UWB device
+ *
+ * Did you call uwb_dev_init() on it?
+ *
+ * @parent_rc: is the parent radio controller who has the link to the
+ * device. When registering the UWB device that is a UWB
+ * Radio Controller, we point back to it.
+ *
+ * If registering the device that is part of a radio, caller has set
+ * rc->uwb_dev->dev. Otherwise it is to be left NULL--a new one will
+ * be allocated.
+ */
+int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
+ struct uwb_rc *parent_rc)
+{
+ int result;
+ struct device *dev;
+
+ BUG_ON(uwb_dev == NULL);
+ BUG_ON(parent_dev == NULL);
+ BUG_ON(parent_rc == NULL);
+
+ mutex_lock(&uwb_dev->mutex);
+ dev = &uwb_dev->dev;
+ uwb_dev->rc = parent_rc;
+ result = __uwb_dev_sys_add(uwb_dev, parent_dev);
+ if (result < 0)
+ printk(KERN_ERR "UWB: unable to register dev %s with sysfs: %d\n",
+ dev_name(dev), result);
+ mutex_unlock(&uwb_dev->mutex);
+ return result;
+}
+
+
+void uwb_dev_rm(struct uwb_dev *uwb_dev)
+{
+ mutex_lock(&uwb_dev->mutex);
+ __uwb_dev_sys_rm(uwb_dev);
+ mutex_unlock(&uwb_dev->mutex);
+}
+
+
+static
+int __uwb_dev_try_get(struct device *dev, void *__target_uwb_dev)
+{
+ struct uwb_dev *target_uwb_dev = __target_uwb_dev;
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ if (uwb_dev == target_uwb_dev) {
+ uwb_dev_get(uwb_dev);
+ return 1;
+ } else
+ return 0;
+}
+
+
+/**
+ * Given a UWB device descriptor, validate and refcount it
+ *
+ * @returns NULL if the device does not exist or is quiescing; the ptr to
+ * it otherwise.
+ */
+struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev)
+{
+ if (uwb_dev_for_each(rc, __uwb_dev_try_get, uwb_dev))
+ return uwb_dev;
+ else
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(uwb_dev_try_get);
+
+
+/**
+ * Remove a device from the system [grunt for other functions]
+ */
+int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc)
+{
+ struct device *dev = &uwb_dev->dev;
+ char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+ uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr);
+ uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr);
+ dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n",
+ macbuf, devbuf,
+ uwb_dev->dev.bus->name,
+ rc ? dev_name(&(rc->uwb_dev.dev)) : "");
+ uwb_dev_rm(uwb_dev);
+ list_del(&uwb_dev->bce->node);
+ uwb_bce_put(uwb_dev->bce);
+ uwb_dev_put(uwb_dev); /* for the creation in _onair() */
+
+ return 0;
+}
+
+
+/**
+ * A device went off the air, clean up after it!
+ *
+ * This is called by the UWB Daemon (through the beacon purge function
+ * uwb_bcn_cache_purge) when it is detected that a device has been in
+ * radio silence for a while.
+ *
+ * If this device is actually a local radio controller we don't need
+ * to go through the offair process, as it is not registered as that.
+ *
+ * NOTE: uwb_bcn_cache.mutex is held!
+ */
+void uwbd_dev_offair(struct uwb_beca_e *bce)
+{
+ struct uwb_dev *uwb_dev;
+
+ uwb_dev = bce->uwb_dev;
+ if (uwb_dev) {
+ uwb_notify(uwb_dev->rc, uwb_dev, UWB_NOTIF_OFFAIR);
+ __uwb_dev_offair(uwb_dev, uwb_dev->rc);
+ }
+}
+
+
+/**
+ * A device went on the air, start it up!
+ *
+ * This is called by the UWB Daemon when it is detected that a device
+ * has popped up in the radio range of the radio controller.
+ *
+ * It will just create the freaking device, register the beacon and
+ * stuff and yatla, done.
+ *
+ *
+ * NOTE: uwb_beca.mutex is held, bce->mutex is held
+ */
+void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_dev *uwb_dev;
+ char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+ uwb_mac_addr_print(macbuf, sizeof(macbuf), bce->mac_addr);
+ uwb_dev_addr_print(devbuf, sizeof(devbuf), &bce->dev_addr);
+ uwb_dev = kzalloc(sizeof(struct uwb_dev), GFP_KERNEL);
+ if (uwb_dev == NULL) {
+ dev_err(dev, "new device %s: Cannot allocate memory\n",
+ macbuf);
+ return;
+ }
+ uwb_dev_init(uwb_dev); /* This sets refcnt to one, we own it */
+ uwb_dev->dev.bus = &uwb_bus_type;
+ uwb_dev->mac_addr = *bce->mac_addr;
+ uwb_dev->dev_addr = bce->dev_addr;
+ dev_set_name(&uwb_dev->dev, "%s", macbuf);
+
+ /* plug the beacon cache */
+ bce->uwb_dev = uwb_dev;
+ uwb_dev->bce = bce;
+ uwb_bce_get(bce); /* released in uwb_dev_sys_release() */
+
+ result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc);
+ if (result < 0) {
+ dev_err(dev, "new device %s: cannot instantiate device\n",
+ macbuf);
+ goto error_dev_add;
+ }
+
+ dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n",
+ macbuf, devbuf, uwb_dev->dev.bus->name,
+ dev_name(&(rc->uwb_dev.dev)));
+ uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR);
+ return;
+
+error_dev_add:
+ bce->uwb_dev = NULL;
+ uwb_bce_put(bce);
+ kfree(uwb_dev);
+ return;
+}
+
+/**
+ * Iterate over the list of UWB devices, calling a @function on each
+ *
+ * See docs for bus_for_each()....
+ *
+ * @rc: radio controller for the devices.
+ * @function: function to call.
+ * @priv: data to pass to @function.
+ * @returns: 0 if no invocation of function() returned a value
+ * different to zero. That value otherwise.
+ */
+int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f function, void *priv)
+{
+ return device_for_each_child(&rc->uwb_dev.dev, priv, function);
+}
+EXPORT_SYMBOL_GPL(uwb_dev_for_each);
diff --git a/drivers/staging/uwb/lc-rc.c b/drivers/staging/uwb/lc-rc.c
new file mode 100644
index 000000000000..ee31b221cdc2
--- /dev/null
+++ b/drivers/staging/uwb/lc-rc.c
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Life cycle of radio controllers
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ *
+ * A UWB radio controller is also a UWB device, so it embeds one...
+ *
+ * List of RCs comes from the 'struct class uwb_rc_class'.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/random.h>
+#include <linux/kdev_t.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "uwb-internal.h"
+
+static int uwb_rc_index_match(struct device *dev, const void *data)
+{
+ const int *index = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc->index == *index)
+ return 1;
+ return 0;
+}
+
+static struct uwb_rc *uwb_rc_find_by_index(int index)
+{
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+ dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match);
+ if (dev) {
+ rc = dev_get_drvdata(dev);
+ put_device(dev);
+ }
+
+ return rc;
+}
+
+static int uwb_rc_new_index(void)
+{
+ int index = 0;
+
+ for (;;) {
+ if (!uwb_rc_find_by_index(index))
+ return index;
+ if (++index < 0)
+ index = 0;
+ }
+}
+
+/**
+ * Release the backing device of a uwb_rc that has been dynamically allocated.
+ */
+static void uwb_rc_sys_release(struct device *dev)
+{
+ struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev);
+ struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev);
+
+ uwb_rc_ie_release(rc);
+ kfree(rc);
+}
+
+
+void uwb_rc_init(struct uwb_rc *rc)
+{
+ struct uwb_dev *uwb_dev = &rc->uwb_dev;
+
+ uwb_dev_init(uwb_dev);
+ rc->uwb_dev.dev.class = &uwb_rc_class;
+ rc->uwb_dev.dev.release = uwb_rc_sys_release;
+ uwb_rc_neh_create(rc);
+ rc->beaconing = -1;
+ rc->scan_type = UWB_SCAN_DISABLED;
+ INIT_LIST_HEAD(&rc->notifs_chain.list);
+ mutex_init(&rc->notifs_chain.mutex);
+ INIT_LIST_HEAD(&rc->uwb_beca.list);
+ mutex_init(&rc->uwb_beca.mutex);
+ uwb_drp_avail_init(rc);
+ uwb_rc_ie_init(rc);
+ uwb_rsv_init(rc);
+ uwb_rc_pal_init(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_init);
+
+
+struct uwb_rc *uwb_rc_alloc(void)
+{
+ struct uwb_rc *rc;
+ rc = kzalloc(sizeof(*rc), GFP_KERNEL);
+ if (rc == NULL)
+ return NULL;
+ uwb_rc_init(rc);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_alloc);
+
+/*
+ * Show the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
+ */
+static ssize_t ASIE_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ struct uwb_ie_hdr *ie;
+ void *ptr;
+ size_t len;
+ int result = 0;
+
+ /* init empty buffer. */
+ result = scnprintf(buf, PAGE_SIZE, "\n");
+ mutex_lock(&rc->ies_mutex);
+ /* walk IEData looking for an ASIE. */
+ ptr = rc->ies->IEData;
+ len = le16_to_cpu(rc->ies->wIELength);
+ for (;;) {
+ ie = uwb_ie_next(&ptr, &len);
+ if (!ie)
+ break;
+ if (ie->element_id == UWB_APP_SPEC_IE) {
+ result = uwb_ie_dump_hex(ie,
+ ie->length + sizeof(struct uwb_ie_hdr),
+ buf, PAGE_SIZE);
+ break;
+ }
+ }
+ mutex_unlock(&rc->ies_mutex);
+
+ return result;
+}
+
+/*
+ * Update the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
+ */
+static ssize_t ASIE_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ char ie_buf[255];
+ int result, ie_len = 0;
+ const char *cur_ptr = buf;
+ struct uwb_ie_hdr *ie;
+
+ /* empty string means clear the ASIE. */
+ if (strlen(buf) <= 1) {
+ uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
+ return size;
+ }
+
+ /* if non-empty string, convert string of hex chars to binary. */
+ while (ie_len < sizeof(ie_buf)) {
+ int char_count;
+
+ if (sscanf(cur_ptr, " %02hhX %n",
+ &(ie_buf[ie_len]), &char_count) > 0) {
+ ++ie_len;
+ /* skip chars read from cur_ptr. */
+ cur_ptr += char_count;
+ } else {
+ break;
+ }
+ }
+
+ /* validate IE length and type. */
+ if (ie_len < sizeof(struct uwb_ie_hdr)) {
+ dev_err(dev, "%s: Invalid ASIE size %d.\n", __func__, ie_len);
+ return -EINVAL;
+ }
+
+ ie = (struct uwb_ie_hdr *)ie_buf;
+ if (ie->element_id != UWB_APP_SPEC_IE) {
+ dev_err(dev, "%s: Invalid IE element type size = 0x%02X.\n",
+ __func__, ie->element_id);
+ return -EINVAL;
+ }
+
+ /* bounds check length field from user. */
+ if (ie->length > (ie_len - sizeof(struct uwb_ie_hdr)))
+ ie->length = ie_len - sizeof(struct uwb_ie_hdr);
+
+ /*
+ * Valid ASIE received. Remove current ASIE then add the new one using
+ * uwb_rc_ie_add.
+ */
+ uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
+
+ result = uwb_rc_ie_add(rc, ie, ie->length + sizeof(struct uwb_ie_hdr));
+
+ return result >= 0 ? size : result;
+}
+static DEVICE_ATTR_RW(ASIE);
+
+static struct attribute *rc_attrs[] = {
+ &dev_attr_mac_address.attr,
+ &dev_attr_scan.attr,
+ &dev_attr_beacon.attr,
+ &dev_attr_ASIE.attr,
+ NULL,
+};
+
+static const struct attribute_group rc_attr_group = {
+ .attrs = rc_attrs,
+};
+
+/*
+ * Registration of sysfs specific stuff
+ */
+static int uwb_rc_sys_add(struct uwb_rc *rc)
+{
+ return sysfs_create_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
+}
+
+
+static void __uwb_rc_sys_rm(struct uwb_rc *rc)
+{
+ sysfs_remove_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
+}
+
+/**
+ * uwb_rc_mac_addr_setup - get an RC's EUI-48 address or set it
+ * @rc: the radio controller.
+ *
+ * If the EUI-48 address is 00:00:00:00:00:00 or FF:FF:FF:FF:FF:FF
+ * then a random locally administered EUI-48 is generated and set on
+ * the device. The probability of address collisions is sufficiently
+ * unlikely (1/2^40 = 9.1e-13) that they're not checked for.
+ */
+static
+int uwb_rc_mac_addr_setup(struct uwb_rc *rc)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_dev *uwb_dev = &rc->uwb_dev;
+ char devname[UWB_ADDR_STRSIZE];
+ struct uwb_mac_addr addr;
+
+ result = uwb_rc_mac_addr_get(rc, &addr);
+ if (result < 0) {
+ dev_err(dev, "cannot retrieve UWB EUI-48 address: %d\n", result);
+ return result;
+ }
+
+ if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) {
+ addr.data[0] = 0x02; /* locally administered and unicast */
+ get_random_bytes(&addr.data[1], sizeof(addr.data)-1);
+
+ result = uwb_rc_mac_addr_set(rc, &addr);
+ if (result < 0) {
+ uwb_mac_addr_print(devname, sizeof(devname), &addr);
+ dev_err(dev, "cannot set EUI-48 address %s: %d\n",
+ devname, result);
+ return result;
+ }
+ }
+ uwb_dev->mac_addr = addr;
+ return 0;
+}
+
+
+
+static int uwb_rc_setup(struct uwb_rc *rc)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ result = uwb_radio_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup UWB radio: %d\n", result);
+ goto error;
+ }
+ result = uwb_rc_mac_addr_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup UWB MAC address: %d\n", result);
+ goto error;
+ }
+ result = uwb_rc_dev_addr_assign(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot assign UWB DevAddr: %d\n", result);
+ goto error;
+ }
+ result = uwb_rc_ie_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup IE subsystem: %d\n", result);
+ goto error_ie_setup;
+ }
+ result = uwb_rsv_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup reservation subsystem: %d\n", result);
+ goto error_rsv_setup;
+ }
+ uwb_dbg_add_rc(rc);
+ return 0;
+
+error_rsv_setup:
+ uwb_rc_ie_release(rc);
+error_ie_setup:
+error:
+ return result;
+}
+
+
+/**
+ * Register a new UWB radio controller
+ *
+ * Did you call uwb_rc_init() on your rc?
+ *
+ * We assume that this is being called with a > 0 refcount on
+ * it [through ops->{get|put}_device(). We'll take our own, though.
+ *
+ * @parent_dev is our real device, the one that provides the actual UWB device
+ */
+int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv)
+{
+ int result;
+ struct device *dev;
+ char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+ rc->index = uwb_rc_new_index();
+
+ dev = &rc->uwb_dev.dev;
+ dev_set_name(dev, "uwb%d", rc->index);
+
+ rc->priv = priv;
+
+ init_waitqueue_head(&rc->uwbd.wq);
+ INIT_LIST_HEAD(&rc->uwbd.event_list);
+ spin_lock_init(&rc->uwbd.event_list_lock);
+
+ uwbd_start(rc);
+
+ result = rc->start(rc);
+ if (result < 0)
+ goto error_rc_start;
+
+ result = uwb_rc_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup UWB radio controller: %d\n", result);
+ goto error_rc_setup;
+ }
+
+ result = uwb_dev_add(&rc->uwb_dev, parent_dev, rc);
+ if (result < 0 && result != -EADDRNOTAVAIL)
+ goto error_dev_add;
+
+ result = uwb_rc_sys_add(rc);
+ if (result < 0) {
+ dev_err(parent_dev, "cannot register UWB radio controller "
+ "dev attributes: %d\n", result);
+ goto error_sys_add;
+ }
+
+ uwb_mac_addr_print(macbuf, sizeof(macbuf), &rc->uwb_dev.mac_addr);
+ uwb_dev_addr_print(devbuf, sizeof(devbuf), &rc->uwb_dev.dev_addr);
+ dev_info(dev,
+ "new uwb radio controller (mac %s dev %s) on %s %s\n",
+ macbuf, devbuf, parent_dev->bus->name, dev_name(parent_dev));
+ rc->ready = 1;
+ return 0;
+
+error_sys_add:
+ uwb_dev_rm(&rc->uwb_dev);
+error_dev_add:
+error_rc_setup:
+ rc->stop(rc);
+error_rc_start:
+ uwbd_stop(rc);
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_add);
+
+
+static int uwb_dev_offair_helper(struct device *dev, void *priv)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+ return __uwb_dev_offair(uwb_dev, uwb_dev->rc);
+}
+
+/*
+ * Remove a Radio Controller; stop beaconing/scanning, disconnect all children
+ */
+void uwb_rc_rm(struct uwb_rc *rc)
+{
+ rc->ready = 0;
+
+ uwb_dbg_del_rc(rc);
+ uwb_rsv_remove_all(rc);
+ uwb_radio_shutdown(rc);
+
+ rc->stop(rc);
+
+ uwbd_stop(rc);
+ uwb_rc_neh_destroy(rc);
+
+ uwb_dev_lock(&rc->uwb_dev);
+ rc->priv = NULL;
+ rc->cmd = NULL;
+ uwb_dev_unlock(&rc->uwb_dev);
+ mutex_lock(&rc->uwb_beca.mutex);
+ uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL);
+ __uwb_rc_sys_rm(rc);
+ mutex_unlock(&rc->uwb_beca.mutex);
+ uwb_rsv_cleanup(rc);
+ uwb_beca_release(rc);
+ uwb_dev_rm(&rc->uwb_dev);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_rm);
+
+static int find_rc_try_get(struct device *dev, const void *data)
+{
+ const struct uwb_rc *target_rc = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc == NULL) {
+ WARN_ON(1);
+ return 0;
+ }
+ if (rc == target_rc) {
+ if (rc->ready == 0)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Given a radio controller descriptor, validate and refcount it
+ *
+ * @returns NULL if the rc does not exist or is quiescing; the ptr to
+ * it otherwise.
+ */
+struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc)
+{
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+ dev = class_find_device(&uwb_rc_class, NULL, target_rc,
+ find_rc_try_get);
+ if (dev) {
+ rc = dev_get_drvdata(dev);
+ __uwb_rc_get(rc);
+ put_device(dev);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(__uwb_rc_try_get);
+
+/*
+ * RC get for external refcount acquirers...
+ *
+ * Increments the refcount of the device and it's backend modules
+ */
+static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc)
+{
+ if (rc->ready == 0)
+ return NULL;
+ uwb_dev_get(&rc->uwb_dev);
+ return rc;
+}
+
+static int find_rc_grandpa(struct device *dev, const void *data)
+{
+ const struct device *grandpa_dev = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc->uwb_dev.dev.parent->parent == grandpa_dev) {
+ rc = uwb_rc_get(rc);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Locate and refcount a radio controller given a common grand-parent
+ *
+ * @grandpa_dev Pointer to the 'grandparent' device structure.
+ * @returns NULL If the rc does not exist or is quiescing; the ptr to
+ * it otherwise, properly referenced.
+ *
+ * The Radio Control interface (or the UWB Radio Controller) is always
+ * an interface of a device. The parent is the interface, the
+ * grandparent is the device that encapsulates the interface.
+ *
+ * There is no need to lock around as the "grandpa" would be
+ * refcounted by the target, and to remove the referemes, the
+ * uwb_rc_class->sem would have to be taken--we hold it, ergo we
+ * should be safe.
+ */
+struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
+{
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+ dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev,
+ find_rc_grandpa);
+ if (dev) {
+ rc = dev_get_drvdata(dev);
+ put_device(dev);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
+
+/**
+ * Find a radio controller by device address
+ *
+ * @returns the pointer to the radio controller, properly referenced
+ */
+static int find_rc_dev(struct device *dev, const void *data)
+{
+ const struct uwb_dev_addr *addr = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc == NULL) {
+ WARN_ON(1);
+ return 0;
+ }
+ if (!uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, addr)) {
+ rc = uwb_rc_get(rc);
+ return 1;
+ }
+ return 0;
+}
+
+struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
+{
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+ dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev);
+ if (dev) {
+ rc = dev_get_drvdata(dev);
+ put_device(dev);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_by_dev);
+
+/**
+ * Drop a reference on a radio controller
+ *
+ * This is the version that should be done by entities external to the
+ * UWB Radio Control stack (ie: clients of the API).
+ */
+void uwb_rc_put(struct uwb_rc *rc)
+{
+ __uwb_rc_put(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_put);
diff --git a/drivers/staging/uwb/neh.c b/drivers/staging/uwb/neh.c
new file mode 100644
index 000000000000..1695584be412
--- /dev/null
+++ b/drivers/staging/uwb/neh.c
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * WUSB Wire Adapter: Radio Control Interface (WUSB[8])
+ * Notification and Event Handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * The RC interface of the Host Wire Adapter (USB dongle) or WHCI PCI
+ * card delivers a stream of notifications and events to the
+ * notification end event endpoint or area. This code takes care of
+ * getting a buffer with that data, breaking it up in separate
+ * notifications and events and then deliver those.
+ *
+ * Events are answers to commands and they carry a context ID that
+ * associates them to the command. Notifications are that,
+ * notifications, they come out of the blue and have a context ID of
+ * zero. Think of the context ID kind of like a handler. The
+ * uwb_rc_neh_* code deals with managing context IDs.
+ *
+ * This is why you require a handle to operate on a UWB host. When you
+ * open a handle a context ID is assigned to you.
+ *
+ * So, as it is done is:
+ *
+ * 1. Add an event handler [uwb_rc_neh_add()] (assigns a ctx id)
+ * 2. Issue command [rc->cmd(rc, ...)]
+ * 3. Arm the timeout timer [uwb_rc_neh_arm()]
+ * 4, Release the reference to the neh [uwb_rc_neh_put()]
+ * 5. Wait for the callback
+ * 6. Command result (RCEB) is passed to the callback
+ *
+ * If (2) fails, you should remove the handle [uwb_rc_neh_rm()]
+ * instead of arming the timer.
+ *
+ * Handles are for using in *serialized* code, single thread.
+ *
+ * When the notification/event comes, the IRQ handler/endpoint
+ * callback passes the data read to uwb_rc_neh_grok() which will break
+ * it up in a discrete series of events, look up who is listening for
+ * them and execute the pertinent callbacks.
+ *
+ * If the reader detects an error while reading the data stream, call
+ * uwb_rc_neh_error().
+ *
+ * CONSTRAINTS/ASSUMPTIONS:
+ *
+ * - Most notifications/events are small (less thank .5k), copying
+ * around is ok.
+ *
+ * - Notifications/events are ALWAYS smaller than PAGE_SIZE
+ *
+ * - Notifications/events always come in a single piece (ie: a buffer
+ * will always contain entire notifications/events).
+ *
+ * - we cannot know in advance how long each event is (because they
+ * lack a length field in their header--smart move by the standards
+ * body, btw). So we need a facility to get the event size given the
+ * header. This is what the EST code does (notif/Event Size
+ * Tables), check nest.c--as well, you can associate the size to
+ * the handle [w/ neh->extra_size()].
+ *
+ * - Most notifications/events are fixed size; only a few are variable
+ * size (NEST takes care of that).
+ *
+ * - Listeners of events expect them, so they usually provide a
+ * buffer, as they know the size. Listeners to notifications don't,
+ * so we allocate their buffers dynamically.
+ */
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/export.h>
+
+#include "uwb-internal.h"
+
+/*
+ * UWB Radio Controller Notification/Event Handle
+ *
+ * Represents an entity waiting for an event coming from the UWB Radio
+ * Controller with a given context id (context) and type (evt_type and
+ * evt). On reception of the notification/event, the callback (cb) is
+ * called with the event.
+ *
+ * If the timer expires before the event is received, the callback is
+ * called with -ETIMEDOUT as the event size.
+ */
+struct uwb_rc_neh {
+ struct kref kref;
+
+ struct uwb_rc *rc;
+ u8 evt_type;
+ __le16 evt;
+ u8 context;
+ u8 completed;
+ uwb_rc_cmd_cb_f cb;
+ void *arg;
+
+ struct timer_list timer;
+ struct list_head list_node;
+};
+
+static void uwb_rc_neh_timer(struct timer_list *t);
+
+static void uwb_rc_neh_release(struct kref *kref)
+{
+ struct uwb_rc_neh *neh = container_of(kref, struct uwb_rc_neh, kref);
+
+ kfree(neh);
+}
+
+static void uwb_rc_neh_get(struct uwb_rc_neh *neh)
+{
+ kref_get(&neh->kref);
+}
+
+/**
+ * uwb_rc_neh_put - release reference to a neh
+ * @neh: the neh
+ */
+void uwb_rc_neh_put(struct uwb_rc_neh *neh)
+{
+ kref_put(&neh->kref, uwb_rc_neh_release);
+}
+
+
+/**
+ * Assigns @neh a context id from @rc's pool
+ *
+ * @rc: UWB Radio Controller descriptor; @rc->neh_lock taken
+ * @neh: Notification/Event Handle
+ * @returns 0 if context id was assigned ok; < 0 errno on error (if
+ * all the context IDs are taken).
+ *
+ * (assumes @wa is locked).
+ *
+ * NOTE: WUSB spec reserves context ids 0x00 for notifications and
+ * 0xff is invalid, so they must not be used. Initialization
+ * fills up those two in the bitmap so they are not allocated.
+ *
+ * We spread the allocation around to reduce the possibility of two
+ * consecutive opened @neh's getting the same context ID assigned (to
+ * avoid surprises with late events that timed out long time ago). So
+ * first we search from where @rc->ctx_roll is, if not found, we
+ * search from zero.
+ */
+static
+int __uwb_rc_ctx_get(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ int result;
+ result = find_next_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX,
+ rc->ctx_roll++);
+ if (result < UWB_RC_CTX_MAX)
+ goto found;
+ result = find_first_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX);
+ if (result < UWB_RC_CTX_MAX)
+ goto found;
+ return -ENFILE;
+found:
+ set_bit(result, rc->ctx_bm);
+ neh->context = result;
+ return 0;
+}
+
+
+/** Releases @neh's context ID back to @rc (@rc->neh_lock is locked). */
+static
+void __uwb_rc_ctx_put(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ if (neh->context == 0)
+ return;
+ if (test_bit(neh->context, rc->ctx_bm) == 0) {
+ dev_err(dev, "context %u not set in bitmap\n",
+ neh->context);
+ WARN_ON(1);
+ }
+ clear_bit(neh->context, rc->ctx_bm);
+ neh->context = 0;
+}
+
+/**
+ * uwb_rc_neh_add - add a neh for a radio controller command
+ * @rc: the radio controller
+ * @cmd: the radio controller command
+ * @expected_type: the type of the expected response event
+ * @expected_event: the expected event ID
+ * @cb: callback for when the event is received
+ * @arg: argument for the callback
+ *
+ * Creates a neh and adds it to the list of those waiting for an
+ * event. A context ID will be assigned to the command.
+ */
+struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
+ u8 expected_type, u16 expected_event,
+ uwb_rc_cmd_cb_f cb, void *arg)
+{
+ int result;
+ unsigned long flags;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_neh *neh;
+
+ neh = kzalloc(sizeof(*neh), GFP_KERNEL);
+ if (neh == NULL) {
+ result = -ENOMEM;
+ goto error_kzalloc;
+ }
+
+ kref_init(&neh->kref);
+ INIT_LIST_HEAD(&neh->list_node);
+ timer_setup(&neh->timer, uwb_rc_neh_timer, 0);
+
+ neh->rc = rc;
+ neh->evt_type = expected_type;
+ neh->evt = cpu_to_le16(expected_event);
+ neh->cb = cb;
+ neh->arg = arg;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ result = __uwb_rc_ctx_get(rc, neh);
+ if (result >= 0) {
+ cmd->bCommandContext = neh->context;
+ list_add_tail(&neh->list_node, &rc->neh_list);
+ uwb_rc_neh_get(neh);
+ }
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+ if (result < 0)
+ goto error_ctx_get;
+
+ return neh;
+
+error_ctx_get:
+ kfree(neh);
+error_kzalloc:
+ dev_err(dev, "cannot open handle to radio controller: %d\n", result);
+ return ERR_PTR(result);
+}
+
+static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ __uwb_rc_ctx_put(rc, neh);
+ list_del(&neh->list_node);
+}
+
+/**
+ * uwb_rc_neh_rm - remove a neh.
+ * @rc: the radio controller
+ * @neh: the neh to remove
+ *
+ * Remove an active neh immediately instead of waiting for the event
+ * (or a time out).
+ */
+void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ __uwb_rc_neh_rm(rc, neh);
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+ del_timer_sync(&neh->timer);
+ uwb_rc_neh_put(neh);
+}
+
+/**
+ * uwb_rc_neh_arm - arm an event handler timeout timer
+ *
+ * @rc: UWB Radio Controller
+ * @neh: Notification/event handler for @rc
+ *
+ * The timer is only armed if the neh is active.
+ */
+void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ if (neh->context)
+ mod_timer(&neh->timer,
+ jiffies + msecs_to_jiffies(UWB_RC_CMD_TIMEOUT_MS));
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+}
+
+static void uwb_rc_neh_cb(struct uwb_rc_neh *neh, struct uwb_rceb *rceb, size_t size)
+{
+ (*neh->cb)(neh->rc, neh->arg, rceb, size);
+ uwb_rc_neh_put(neh);
+}
+
+static bool uwb_rc_neh_match(struct uwb_rc_neh *neh, const struct uwb_rceb *rceb)
+{
+ return neh->evt_type == rceb->bEventType
+ && neh->evt == rceb->wEvent
+ && neh->context == rceb->bEventContext;
+}
+
+/**
+ * Find the handle waiting for a RC Radio Control Event
+ *
+ * @rc: UWB Radio Controller
+ * @rceb: Pointer to the RCEB buffer
+ * @event_size: Pointer to the size of the RCEB buffer. Might be
+ * adjusted to take into account the @neh->extra_size
+ * settings.
+ *
+ * If the listener has no buffer (NULL buffer), one is allocated for
+ * the right size (the amount of data received). @neh->ptr will point
+ * to the event payload, which always starts with a 'struct
+ * uwb_rceb'. kfree() it when done.
+ */
+static
+struct uwb_rc_neh *uwb_rc_neh_lookup(struct uwb_rc *rc,
+ const struct uwb_rceb *rceb)
+{
+ struct uwb_rc_neh *neh = NULL, *h;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+
+ list_for_each_entry(h, &rc->neh_list, list_node) {
+ if (uwb_rc_neh_match(h, rceb)) {
+ neh = h;
+ break;
+ }
+ }
+
+ if (neh)
+ __uwb_rc_neh_rm(rc, neh);
+
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+ return neh;
+}
+
+
+/*
+ * Process notifications coming from the radio control interface
+ *
+ * @rc: UWB Radio Control Interface descriptor
+ * @neh: Notification/Event Handler @neh->ptr points to
+ * @uwb_evt->buffer.
+ *
+ * This function is called by the event/notif handling subsystem when
+ * notifications arrive (hwarc_probe() arms a notification/event handle
+ * that calls back this function for every received notification; this
+ * function then will rearm itself).
+ *
+ * Notification data buffers are dynamically allocated by the NEH
+ * handling code in neh.c [uwb_rc_neh_lookup()]. What is actually
+ * allocated is space to contain the notification data.
+ *
+ * Buffers are prefixed with a Radio Control Event Block (RCEB) as
+ * defined by the WUSB Wired-Adapter Radio Control interface. We
+ * just use it for the notification code.
+ *
+ * On each case statement we just transcode endianess of the different
+ * fields. We declare a pointer to a RCI definition of an event, and
+ * then to a UWB definition of the same event (which are the same,
+ * remember). Event if we use different pointers
+ */
+static
+void uwb_rc_notif(struct uwb_rc *rc, struct uwb_rceb *rceb, ssize_t size)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_event *uwb_evt;
+
+ if (size == -ESHUTDOWN)
+ return;
+ if (size < 0) {
+ dev_err(dev, "ignoring event with error code %zu\n",
+ size);
+ return;
+ }
+
+ uwb_evt = kzalloc(sizeof(*uwb_evt), GFP_ATOMIC);
+ if (unlikely(uwb_evt == NULL)) {
+ dev_err(dev, "no memory to queue event 0x%02x/%04x/%02x\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext);
+ return;
+ }
+ uwb_evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */
+ uwb_evt->ts_jiffies = jiffies;
+ uwb_evt->type = UWB_EVT_TYPE_NOTIF;
+ uwb_evt->notif.size = size;
+ uwb_evt->notif.rceb = rceb;
+
+ uwbd_event_queue(uwb_evt);
+}
+
+static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size_t size)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_neh *neh;
+ struct uwb_rceb *notif;
+ unsigned long flags;
+
+ if (rceb->bEventContext == 0) {
+ notif = kmalloc(size, GFP_ATOMIC);
+ if (notif) {
+ memcpy(notif, rceb, size);
+ uwb_rc_notif(rc, notif, size);
+ } else
+ dev_err(dev, "event 0x%02x/%04x/%02x (%zu bytes): no memory\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext, size);
+ } else {
+ neh = uwb_rc_neh_lookup(rc, rceb);
+ if (neh) {
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ /* to guard against a timeout */
+ neh->completed = 1;
+ del_timer(&neh->timer);
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+ uwb_rc_neh_cb(neh, rceb, size);
+ } else
+ dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext, size);
+ }
+}
+
+/**
+ * Given a buffer with one or more UWB RC events/notifications, break
+ * them up and dispatch them.
+ *
+ * @rc: UWB Radio Controller
+ * @buf: Buffer with the stream of notifications/events
+ * @buf_size: Amount of data in the buffer
+ *
+ * Note each notification/event starts always with a 'struct
+ * uwb_rceb', so the minimum size if 4 bytes.
+ *
+ * The device may pass us events formatted differently than expected.
+ * These are first filtered, potentially creating a new event in a new
+ * memory location. If a new event is created by the filter it is also
+ * freed here.
+ *
+ * For each notif/event, tries to guess the size looking at the EST
+ * tables, then looks for a neh that is waiting for that event and if
+ * found, copies the payload to the neh's buffer and calls it back. If
+ * not, the data is ignored.
+ *
+ * Note that if we can't find a size description in the EST tables, we
+ * still might find a size in the 'neh' handle in uwb_rc_neh_lookup().
+ *
+ * Assumptions:
+ *
+ * @rc->neh_lock is NOT taken
+ *
+ * We keep track of various sizes here:
+ * size: contains the size of the buffer that is processed for the
+ * incoming event. this buffer may contain events that are not
+ * formatted as WHCI.
+ * real_size: the actual space taken by this event in the buffer.
+ * We need to keep track of the real size of an event to be able to
+ * advance the buffer correctly.
+ * event_size: the size of the event as expected by the core layer
+ * [OR] the size of the event after filtering. if the filtering
+ * created a new event in a new memory location then this is
+ * effectively the size of a new event buffer
+ */
+void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ void *itr;
+ struct uwb_rceb *rceb;
+ size_t size, real_size, event_size;
+ int needtofree;
+
+ itr = buf;
+ size = buf_size;
+ while (size > 0) {
+ if (size < sizeof(*rceb)) {
+ dev_err(dev, "not enough data in event buffer to "
+ "process incoming events (%zu left, minimum is "
+ "%zu)\n", size, sizeof(*rceb));
+ break;
+ }
+
+ rceb = itr;
+ if (rc->filter_event) {
+ needtofree = rc->filter_event(rc, &rceb, size,
+ &real_size, &event_size);
+ if (needtofree < 0 && needtofree != -ENOANO) {
+ dev_err(dev, "BUG: Unable to filter event "
+ "(0x%02x/%04x/%02x) from "
+ "device. \n", rceb->bEventType,
+ le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext);
+ break;
+ }
+ } else
+ needtofree = -ENOANO;
+ /* do real processing if there was no filtering or the
+ * filtering didn't act */
+ if (needtofree == -ENOANO) {
+ ssize_t ret = uwb_est_find_size(rc, rceb, size);
+ if (ret < 0)
+ break;
+ if (ret > size) {
+ dev_err(dev, "BUG: hw sent incomplete event "
+ "0x%02x/%04x/%02x (%zd bytes), only got "
+ "%zu bytes. We don't handle that.\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext, ret, size);
+ break;
+ }
+ real_size = event_size = ret;
+ }
+ uwb_rc_neh_grok_event(rc, rceb, event_size);
+
+ if (needtofree == 1)
+ kfree(rceb);
+
+ itr += real_size;
+ size -= real_size;
+ }
+}
+EXPORT_SYMBOL_GPL(uwb_rc_neh_grok);
+
+
+/**
+ * The entity that reads from the device notification/event channel has
+ * detected an error.
+ *
+ * @rc: UWB Radio Controller
+ * @error: Errno error code
+ *
+ */
+void uwb_rc_neh_error(struct uwb_rc *rc, int error)
+{
+ struct uwb_rc_neh *neh;
+ unsigned long flags;
+
+ for (;;) {
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ if (list_empty(&rc->neh_list)) {
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+ break;
+ }
+ neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
+ __uwb_rc_neh_rm(rc, neh);
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+ del_timer_sync(&neh->timer);
+ uwb_rc_neh_cb(neh, NULL, error);
+ }
+}
+EXPORT_SYMBOL_GPL(uwb_rc_neh_error);
+
+
+static void uwb_rc_neh_timer(struct timer_list *t)
+{
+ struct uwb_rc_neh *neh = from_timer(neh, t, timer);
+ struct uwb_rc *rc = neh->rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ if (neh->completed) {
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+ return;
+ }
+ if (neh->context)
+ __uwb_rc_neh_rm(rc, neh);
+ else
+ neh = NULL;
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+ if (neh)
+ uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT);
+}
+
+/** Initializes the @rc's neh subsystem
+ */
+void uwb_rc_neh_create(struct uwb_rc *rc)
+{
+ spin_lock_init(&rc->neh_lock);
+ INIT_LIST_HEAD(&rc->neh_list);
+ set_bit(0, rc->ctx_bm); /* 0 is reserved (see [WUSB] table 8-65) */
+ set_bit(0xff, rc->ctx_bm); /* and 0xff is invalid */
+ rc->ctx_roll = 1;
+}
+
+
+/** Release's the @rc's neh subsystem */
+void uwb_rc_neh_destroy(struct uwb_rc *rc)
+{
+ unsigned long flags;
+ struct uwb_rc_neh *neh;
+
+ for (;;) {
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ if (list_empty(&rc->neh_list)) {
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+ break;
+ }
+ neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
+ __uwb_rc_neh_rm(rc, neh);
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+ del_timer_sync(&neh->timer);
+ uwb_rc_neh_put(neh);
+ }
+}
diff --git a/drivers/staging/uwb/pal.c b/drivers/staging/uwb/pal.c
new file mode 100644
index 000000000000..a541e646a603
--- /dev/null
+++ b/drivers/staging/uwb/pal.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB PAL support.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/export.h>
+
+#include "uwb.h"
+#include "uwb-internal.h"
+
+/**
+ * uwb_pal_init - initialize a UWB PAL
+ * @pal: the PAL to initialize
+ */
+void uwb_pal_init(struct uwb_pal *pal)
+{
+ INIT_LIST_HEAD(&pal->node);
+}
+EXPORT_SYMBOL_GPL(uwb_pal_init);
+
+/**
+ * uwb_pal_register - register a UWB PAL
+ * @pal: the PAL
+ *
+ * The PAL must be initialized with uwb_pal_init().
+ */
+int uwb_pal_register(struct uwb_pal *pal)
+{
+ struct uwb_rc *rc = pal->rc;
+ int ret;
+
+ if (pal->device) {
+ /* create a link to the uwb_rc in the PAL device's directory. */
+ ret = sysfs_create_link(&pal->device->kobj,
+ &rc->uwb_dev.dev.kobj, "uwb_rc");
+ if (ret < 0)
+ return ret;
+ /* create a link to the PAL in the UWB device's directory. */
+ ret = sysfs_create_link(&rc->uwb_dev.dev.kobj,
+ &pal->device->kobj, pal->name);
+ if (ret < 0) {
+ sysfs_remove_link(&pal->device->kobj, "uwb_rc");
+ return ret;
+ }
+ }
+
+ pal->debugfs_dir = uwb_dbg_create_pal_dir(pal);
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ list_add(&pal->node, &rc->pals);
+ mutex_unlock(&rc->uwb_dev.mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_pal_register);
+
+static int find_rc(struct device *dev, const void *data)
+{
+ const struct uwb_rc *target_rc = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc == NULL) {
+ WARN_ON(1);
+ return 0;
+ }
+ if (rc == target_rc) {
+ if (rc->ready == 0)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Given a radio controller descriptor see if it is registered.
+ *
+ * @returns false if the rc does not exist or is quiescing; true otherwise.
+ */
+static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc)
+{
+ struct device *dev;
+
+ dev = class_find_device(&uwb_rc_class, NULL, target_rc, find_rc);
+
+ put_device(dev);
+
+ return (dev != NULL);
+}
+
+/**
+ * uwb_pal_unregister - unregister a UWB PAL
+ * @pal: the PAL
+ */
+void uwb_pal_unregister(struct uwb_pal *pal)
+{
+ struct uwb_rc *rc = pal->rc;
+
+ uwb_radio_stop(pal);
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ list_del(&pal->node);
+ mutex_unlock(&rc->uwb_dev.mutex);
+
+ debugfs_remove(pal->debugfs_dir);
+
+ if (pal->device) {
+ /* remove link to the PAL in the UWB device's directory. */
+ if (uwb_rc_class_device_exists(rc))
+ sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+
+ /* remove link to uwb_rc in the PAL device's directory. */
+ sysfs_remove_link(&pal->device->kobj, "uwb_rc");
+ }
+}
+EXPORT_SYMBOL_GPL(uwb_pal_unregister);
+
+/**
+ * uwb_rc_pal_init - initialize the PAL related parts of a radio controller
+ * @rc: the radio controller
+ */
+void uwb_rc_pal_init(struct uwb_rc *rc)
+{
+ INIT_LIST_HEAD(&rc->pals);
+}
diff --git a/drivers/staging/uwb/radio.c b/drivers/staging/uwb/radio.c
new file mode 100644
index 000000000000..6afb75ce1b5f
--- /dev/null
+++ b/drivers/staging/uwb/radio.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB radio (channel) management.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+
+#include "uwb.h"
+#include "uwb-internal.h"
+
+
+static int uwb_radio_select_channel(struct uwb_rc *rc)
+{
+ /*
+ * Default to channel 9 (BG1, TFC1) unless the user has
+ * selected a specific channel or there are no active PALs.
+ */
+ if (rc->active_pals == 0)
+ return -1;
+ if (rc->beaconing_forced)
+ return rc->beaconing_forced;
+ return 9;
+}
+
+
+/*
+ * Notify all active PALs that the channel has changed.
+ */
+static void uwb_radio_channel_changed(struct uwb_rc *rc, int channel)
+{
+ struct uwb_pal *pal;
+
+ list_for_each_entry(pal, &rc->pals, node) {
+ if (pal->channel && channel != pal->channel) {
+ pal->channel = channel;
+ if (pal->channel_changed)
+ pal->channel_changed(pal, pal->channel);
+ }
+ }
+}
+
+/*
+ * Change to a new channel and notify any active PALs of the new
+ * channel.
+ *
+ * When stopping the radio, PALs need to be notified first so they can
+ * terminate any active reservations.
+ */
+static int uwb_radio_change_channel(struct uwb_rc *rc, int channel)
+{
+ int ret = 0;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ dev_dbg(dev, "%s: channel = %d, rc->beaconing = %d\n", __func__,
+ channel, rc->beaconing);
+
+ if (channel == -1)
+ uwb_radio_channel_changed(rc, channel);
+
+ if (channel != rc->beaconing) {
+ if (rc->beaconing != -1 && channel != -1) {
+ /*
+ * FIXME: should signal the channel change
+ * with a Channel Change IE.
+ */
+ ret = uwb_radio_change_channel(rc, -1);
+ if (ret < 0)
+ return ret;
+ }
+ ret = uwb_rc_beacon(rc, channel, 0);
+ }
+
+ if (channel != -1)
+ uwb_radio_channel_changed(rc, rc->beaconing);
+
+ return ret;
+}
+
+/**
+ * uwb_radio_start - request that the radio be started
+ * @pal: the PAL making the request.
+ *
+ * If the radio is not already active, a suitable channel is selected
+ * and beacons are started.
+ */
+int uwb_radio_start(struct uwb_pal *pal)
+{
+ struct uwb_rc *rc = pal->rc;
+ int ret = 0;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+
+ if (!pal->channel) {
+ pal->channel = -1;
+ rc->active_pals++;
+ ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
+ }
+
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(uwb_radio_start);
+
+/**
+ * uwb_radio_stop - request that the radio be stopped.
+ * @pal: the PAL making the request.
+ *
+ * Stops the radio if no other PAL is making use of it.
+ */
+void uwb_radio_stop(struct uwb_pal *pal)
+{
+ struct uwb_rc *rc = pal->rc;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+
+ if (pal->channel) {
+ rc->active_pals--;
+ uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
+ pal->channel = 0;
+ }
+
+ mutex_unlock(&rc->uwb_dev.mutex);
+}
+EXPORT_SYMBOL_GPL(uwb_radio_stop);
+
+/*
+ * uwb_radio_force_channel - force a specific channel to be used
+ * @rc: the radio controller.
+ * @channel: the channel to use; -1 to force the radio to stop; 0 to
+ * use the default channel selection algorithm.
+ */
+int uwb_radio_force_channel(struct uwb_rc *rc, int channel)
+{
+ int ret = 0;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+
+ rc->beaconing_forced = channel;
+ ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
+
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return ret;
+}
+
+/*
+ * uwb_radio_setup - setup the radio manager
+ * @rc: the radio controller.
+ *
+ * The radio controller is reset to ensure it's in a known state
+ * before it's used.
+ */
+int uwb_radio_setup(struct uwb_rc *rc)
+{
+ return uwb_rc_reset(rc);
+}
+
+/*
+ * uwb_radio_reset_state - reset any radio manager state
+ * @rc: the radio controller.
+ *
+ * All internal radio manager state is reset to values corresponding
+ * to a reset radio controller.
+ */
+void uwb_radio_reset_state(struct uwb_rc *rc)
+{
+ struct uwb_pal *pal;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+
+ list_for_each_entry(pal, &rc->pals, node) {
+ if (pal->channel) {
+ pal->channel = -1;
+ if (pal->channel_changed)
+ pal->channel_changed(pal, -1);
+ }
+ }
+
+ rc->beaconing = -1;
+ rc->scanning = -1;
+
+ mutex_unlock(&rc->uwb_dev.mutex);
+}
+
+/*
+ * uwb_radio_shutdown - shutdown the radio manager
+ * @rc: the radio controller.
+ *
+ * The radio controller is reset.
+ */
+void uwb_radio_shutdown(struct uwb_rc *rc)
+{
+ uwb_radio_reset_state(rc);
+ uwb_rc_reset(rc);
+}
diff --git a/drivers/staging/uwb/reset.c b/drivers/staging/uwb/reset.c
new file mode 100644
index 000000000000..8fc7c14d903e
--- /dev/null
+++ b/drivers/staging/uwb/reset.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * UWB basic command support and radio reset
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME:
+ *
+ * - docs
+ *
+ * - Now we are serializing (using the uwb_dev->mutex) the command
+ * execution; it should be parallelized as much as possible some
+ * day.
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+
+#include "uwb-internal.h"
+
+/**
+ * Command result codes (WUSB1.0[T8-69])
+ */
+static
+const char *__strerror[] = {
+ "success",
+ "failure",
+ "hardware failure",
+ "no more slots",
+ "beacon is too large",
+ "invalid parameter",
+ "unsupported power level",
+ "time out (wa) or invalid ie data (whci)",
+ "beacon size exceeded",
+ "cancelled",
+ "invalid state",
+ "invalid size",
+ "ack not received",
+ "no more asie notification",
+};
+
+
+/** Return a string matching the given error code */
+const char *uwb_rc_strerror(unsigned code)
+{
+ if (code == 255)
+ return "time out";
+ if (code >= ARRAY_SIZE(__strerror))
+ return "unknown error";
+ return __strerror[code];
+}
+
+int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ u8 expected_type, u16 expected_event,
+ uwb_rc_cmd_cb_f cb, void *arg)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_neh *neh;
+ int needtofree = 0;
+ int result;
+
+ uwb_dev_lock(&rc->uwb_dev); /* Protect against rc->priv being removed */
+ if (rc->priv == NULL) {
+ uwb_dev_unlock(&rc->uwb_dev);
+ return -ESHUTDOWN;
+ }
+
+ if (rc->filter_cmd) {
+ needtofree = rc->filter_cmd(rc, &cmd, &cmd_size);
+ if (needtofree < 0 && needtofree != -ENOANO) {
+ dev_err(dev, "%s: filter error: %d\n",
+ cmd_name, needtofree);
+ uwb_dev_unlock(&rc->uwb_dev);
+ return needtofree;
+ }
+ }
+
+ neh = uwb_rc_neh_add(rc, cmd, expected_type, expected_event, cb, arg);
+ if (IS_ERR(neh)) {
+ result = PTR_ERR(neh);
+ uwb_dev_unlock(&rc->uwb_dev);
+ goto out;
+ }
+
+ result = rc->cmd(rc, cmd, cmd_size);
+ uwb_dev_unlock(&rc->uwb_dev);
+ if (result < 0)
+ uwb_rc_neh_rm(rc, neh);
+ else
+ uwb_rc_neh_arm(rc, neh);
+ uwb_rc_neh_put(neh);
+out:
+ if (needtofree == 1)
+ kfree(cmd);
+ return result < 0 ? result : 0;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_cmd_async);
+
+struct uwb_rc_cmd_done_params {
+ struct completion completion;
+ struct uwb_rceb *reply;
+ ssize_t reply_size;
+};
+
+static void uwb_rc_cmd_done(struct uwb_rc *rc, void *arg,
+ struct uwb_rceb *reply, ssize_t reply_size)
+{
+ struct uwb_rc_cmd_done_params *p = (struct uwb_rc_cmd_done_params *)arg;
+
+ if (reply_size > 0) {
+ if (p->reply)
+ reply_size = min(p->reply_size, reply_size);
+ else
+ p->reply = kmalloc(reply_size, GFP_ATOMIC);
+
+ if (p->reply)
+ memcpy(p->reply, reply, reply_size);
+ else
+ reply_size = -ENOMEM;
+ }
+ p->reply_size = reply_size;
+ complete(&p->completion);
+}
+
+
+/**
+ * Generic function for issuing commands to the Radio Control Interface
+ *
+ * @rc: UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd: Pointer to rccb structure containing the command;
+ * normally you embed this structure as the first member of
+ * the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @reply: Pointer to where to store the reply
+ * @reply_size: @reply's size
+ * @expected_type: Expected type in the return event
+ * @expected_event: Expected event code in the return event
+ * @preply: Here a pointer to where the event data is received will
+ * be stored. Once done with the data, free with kfree().
+ *
+ * This function is generic; it works for commands that return a fixed
+ * and known size or for commands that return a variable amount of data.
+ *
+ * If a buffer is provided, that is used, although it could be chopped
+ * to the maximum size of the buffer. If the buffer is NULL, then one
+ * be allocated in *preply with the whole contents of the reply.
+ *
+ * @rc needs to be referenced
+ */
+static
+ssize_t __uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ struct uwb_rceb *reply, size_t reply_size,
+ u8 expected_type, u16 expected_event,
+ struct uwb_rceb **preply)
+{
+ ssize_t result = 0;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_cmd_done_params params;
+
+ init_completion(&params.completion);
+ params.reply = reply;
+ params.reply_size = reply_size;
+
+ result = uwb_rc_cmd_async(rc, cmd_name, cmd, cmd_size,
+ expected_type, expected_event,
+ uwb_rc_cmd_done, &params);
+ if (result)
+ return result;
+
+ wait_for_completion(&params.completion);
+
+ if (preply)
+ *preply = params.reply;
+
+ if (params.reply_size < 0)
+ dev_err(dev, "%s: confirmation event 0x%02x/%04x/%02x "
+ "reception failed: %d\n", cmd_name,
+ expected_type, expected_event, cmd->bCommandContext,
+ (int)params.reply_size);
+ return params.reply_size;
+}
+
+
+/**
+ * Generic function for issuing commands to the Radio Control Interface
+ *
+ * @rc: UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd: Pointer to rccb structure containing the command;
+ * normally you embed this structure as the first member of
+ * the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @reply: Pointer to the beginning of the confirmation event
+ * buffer. Normally bigger than an 'struct hwarc_rceb'.
+ * You need to fill out reply->bEventType and reply->wEvent (in
+ * cpu order) as the function will use them to verify the
+ * confirmation event.
+ * @reply_size: Size of the reply buffer
+ *
+ * The function checks that the length returned in the reply is at
+ * least as big as @reply_size; if not, it will be deemed an error and
+ * -EIO returned.
+ *
+ * @rc needs to be referenced
+ */
+ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ struct uwb_rceb *reply, size_t reply_size)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ ssize_t result;
+
+ result = __uwb_rc_cmd(rc, cmd_name,
+ cmd, cmd_size, reply, reply_size,
+ reply->bEventType, reply->wEvent, NULL);
+
+ if (result > 0 && result < reply_size) {
+ dev_err(dev, "%s: not enough data returned for decoding reply "
+ "(%zu bytes received vs at least %zu needed)\n",
+ cmd_name, result, reply_size);
+ result = -EIO;
+ }
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_cmd);
+
+
+/**
+ * Generic function for issuing commands to the Radio Control
+ * Interface that return an unknown amount of data
+ *
+ * @rc: UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd: Pointer to rccb structure containing the command;
+ * normally you embed this structure as the first member of
+ * the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @expected_type: Expected type in the return event
+ * @expected_event: Expected event code in the return event
+ * @preply: Here a pointer to where the event data is received will
+ * be stored. Once done with the data, free with kfree().
+ *
+ * The function checks that the length returned in the reply is at
+ * least as big as a 'struct uwb_rceb *'; if not, it will be deemed an
+ * error and -EIO returned.
+ *
+ * @rc needs to be referenced
+ */
+ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ u8 expected_type, u16 expected_event,
+ struct uwb_rceb **preply)
+{
+ return __uwb_rc_cmd(rc, cmd_name, cmd, cmd_size, NULL, 0,
+ expected_type, expected_event, preply);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_vcmd);
+
+
+/**
+ * Reset a UWB Host Controller (and all radio settings)
+ *
+ * @rc: Host Controller descriptor
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ */
+int uwb_rc_reset(struct uwb_rc *rc)
+{
+ int result = -ENOMEM;
+ struct uwb_rc_evt_confirm reply;
+ struct uwb_rccb *cmd;
+ size_t cmd_size = sizeof(*cmd);
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_kzalloc;
+ cmd->bCommandType = UWB_RC_CET_GENERAL;
+ cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_RESET;
+ result = uwb_rc_cmd(rc, "RESET", cmd, cmd_size,
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "RESET: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ }
+error_cmd:
+ kfree(cmd);
+error_kzalloc:
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+int uwbd_msg_handle_reset(struct uwb_event *evt)
+{
+ struct uwb_rc *rc = evt->rc;
+ int ret;
+
+ dev_info(&rc->uwb_dev.dev, "resetting radio controller\n");
+ ret = rc->reset(rc);
+ if (ret < 0) {
+ dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret);
+ goto error;
+ }
+ return 0;
+error:
+ /* Nothing can be done except try the reset again. Wait a bit
+ to avoid reset loops during probe() or remove(). */
+ msleep(1000);
+ uwb_rc_reset_all(rc);
+ return ret;
+}
+
+/**
+ * uwb_rc_reset_all - request a reset of the radio controller and PALs
+ * @rc: the radio controller of the hardware device to be reset.
+ *
+ * The full hardware reset of the radio controller and all the PALs
+ * will be scheduled.
+ */
+void uwb_rc_reset_all(struct uwb_rc *rc)
+{
+ struct uwb_event *evt;
+
+ evt = kzalloc(sizeof(struct uwb_event), GFP_ATOMIC);
+ if (unlikely(evt == NULL))
+ return;
+
+ evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */
+ evt->ts_jiffies = jiffies;
+ evt->type = UWB_EVT_TYPE_MSG;
+ evt->message = UWB_EVT_MSG_RESET;
+
+ uwbd_event_queue(evt);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_reset_all);
+
+void uwb_rc_pre_reset(struct uwb_rc *rc)
+{
+ rc->stop(rc);
+ uwbd_flush(rc);
+
+ uwb_radio_reset_state(rc);
+ uwb_rsv_remove_all(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_pre_reset);
+
+int uwb_rc_post_reset(struct uwb_rc *rc)
+{
+ int ret;
+
+ ret = rc->start(rc);
+ if (ret)
+ goto out;
+ ret = uwb_rc_mac_addr_set(rc, &rc->uwb_dev.mac_addr);
+ if (ret)
+ goto out;
+ ret = uwb_rc_dev_addr_set(rc, &rc->uwb_dev.dev_addr);
+ if (ret)
+ goto out;
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_post_reset);
diff --git a/drivers/staging/uwb/rsv.c b/drivers/staging/uwb/rsv.c
new file mode 100644
index 000000000000..f45a04ff7275
--- /dev/null
+++ b/drivers/staging/uwb/rsv.c
@@ -0,0 +1,1000 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB reservation management.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/export.h>
+
+#include "uwb.h"
+#include "uwb-internal.h"
+
+static void uwb_rsv_timer(struct timer_list *t);
+
+static const char *rsv_states[] = {
+ [UWB_RSV_STATE_NONE] = "none ",
+ [UWB_RSV_STATE_O_INITIATED] = "o initiated ",
+ [UWB_RSV_STATE_O_PENDING] = "o pending ",
+ [UWB_RSV_STATE_O_MODIFIED] = "o modified ",
+ [UWB_RSV_STATE_O_ESTABLISHED] = "o established ",
+ [UWB_RSV_STATE_O_TO_BE_MOVED] = "o to be moved ",
+ [UWB_RSV_STATE_O_MOVE_EXPANDING] = "o move expanding",
+ [UWB_RSV_STATE_O_MOVE_COMBINING] = "o move combining",
+ [UWB_RSV_STATE_O_MOVE_REDUCING] = "o move reducing ",
+ [UWB_RSV_STATE_T_ACCEPTED] = "t accepted ",
+ [UWB_RSV_STATE_T_CONFLICT] = "t conflict ",
+ [UWB_RSV_STATE_T_PENDING] = "t pending ",
+ [UWB_RSV_STATE_T_DENIED] = "t denied ",
+ [UWB_RSV_STATE_T_RESIZED] = "t resized ",
+ [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = "t expanding acc ",
+ [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = "t expanding conf",
+ [UWB_RSV_STATE_T_EXPANDING_PENDING] = "t expanding pend",
+ [UWB_RSV_STATE_T_EXPANDING_DENIED] = "t expanding den ",
+};
+
+static const char *rsv_types[] = {
+ [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp",
+ [UWB_DRP_TYPE_HARD] = "hard",
+ [UWB_DRP_TYPE_SOFT] = "soft",
+ [UWB_DRP_TYPE_PRIVATE] = "private",
+ [UWB_DRP_TYPE_PCA] = "pca",
+};
+
+bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv)
+{
+ static const bool has_two_drp_ies[] = {
+ [UWB_RSV_STATE_O_INITIATED] = false,
+ [UWB_RSV_STATE_O_PENDING] = false,
+ [UWB_RSV_STATE_O_MODIFIED] = false,
+ [UWB_RSV_STATE_O_ESTABLISHED] = false,
+ [UWB_RSV_STATE_O_TO_BE_MOVED] = false,
+ [UWB_RSV_STATE_O_MOVE_COMBINING] = false,
+ [UWB_RSV_STATE_O_MOVE_REDUCING] = false,
+ [UWB_RSV_STATE_O_MOVE_EXPANDING] = true,
+ [UWB_RSV_STATE_T_ACCEPTED] = false,
+ [UWB_RSV_STATE_T_CONFLICT] = false,
+ [UWB_RSV_STATE_T_PENDING] = false,
+ [UWB_RSV_STATE_T_DENIED] = false,
+ [UWB_RSV_STATE_T_RESIZED] = false,
+ [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = true,
+ [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = true,
+ [UWB_RSV_STATE_T_EXPANDING_PENDING] = true,
+ [UWB_RSV_STATE_T_EXPANDING_DENIED] = true,
+ };
+
+ return has_two_drp_ies[rsv->state];
+}
+
+/**
+ * uwb_rsv_state_str - return a string for a reservation state
+ * @state: the reservation state.
+ */
+const char *uwb_rsv_state_str(enum uwb_rsv_state state)
+{
+ if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST)
+ return "unknown";
+ return rsv_states[state];
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_state_str);
+
+/**
+ * uwb_rsv_type_str - return a string for a reservation type
+ * @type: the reservation type
+ */
+const char *uwb_rsv_type_str(enum uwb_drp_type type)
+{
+ if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA)
+ return "invalid";
+ return rsv_types[type];
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_type_str);
+
+void uwb_rsv_dump(char *text, struct uwb_rsv *rsv)
+{
+ struct device *dev = &rsv->rc->uwb_dev.dev;
+ struct uwb_dev_addr devaddr;
+ char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
+
+ uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
+ if (rsv->target.type == UWB_RSV_TARGET_DEV)
+ devaddr = rsv->target.dev->dev_addr;
+ else
+ devaddr = rsv->target.devaddr;
+ uwb_dev_addr_print(target, sizeof(target), &devaddr);
+
+ dev_dbg(dev, "rsv %s %s -> %s: %s\n",
+ text, owner, target, uwb_rsv_state_str(rsv->state));
+}
+
+static void uwb_rsv_release(struct kref *kref)
+{
+ struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref);
+
+ kfree(rsv);
+}
+
+void uwb_rsv_get(struct uwb_rsv *rsv)
+{
+ kref_get(&rsv->kref);
+}
+
+void uwb_rsv_put(struct uwb_rsv *rsv)
+{
+ kref_put(&rsv->kref, uwb_rsv_release);
+}
+
+/*
+ * Get a free stream index for a reservation.
+ *
+ * If the target is a DevAddr (e.g., a WUSB cluster reservation) then
+ * the stream is allocated from a pool of per-RC stream indexes,
+ * otherwise a unique stream index for the target is selected.
+ */
+static int uwb_rsv_get_stream(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+ struct device *dev = &rc->uwb_dev.dev;
+ unsigned long *streams_bm;
+ int stream;
+
+ switch (rsv->target.type) {
+ case UWB_RSV_TARGET_DEV:
+ streams_bm = rsv->target.dev->streams;
+ break;
+ case UWB_RSV_TARGET_DEVADDR:
+ streams_bm = rc->uwb_dev.streams;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS);
+ if (stream >= UWB_NUM_STREAMS) {
+ dev_err(dev, "%s: no available stream found\n", __func__);
+ return -EBUSY;
+ }
+
+ rsv->stream = stream;
+ set_bit(stream, streams_bm);
+
+ dev_dbg(dev, "get stream %d\n", rsv->stream);
+
+ return 0;
+}
+
+static void uwb_rsv_put_stream(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+ struct device *dev = &rc->uwb_dev.dev;
+ unsigned long *streams_bm;
+
+ switch (rsv->target.type) {
+ case UWB_RSV_TARGET_DEV:
+ streams_bm = rsv->target.dev->streams;
+ break;
+ case UWB_RSV_TARGET_DEVADDR:
+ streams_bm = rc->uwb_dev.streams;
+ break;
+ default:
+ return;
+ }
+
+ clear_bit(rsv->stream, streams_bm);
+
+ dev_dbg(dev, "put stream %d\n", rsv->stream);
+}
+
+void uwb_rsv_backoff_win_timer(struct timer_list *t)
+{
+ struct uwb_drp_backoff_win *bow = from_timer(bow, t, timer);
+ struct uwb_rc *rc = container_of(bow, struct uwb_rc, bow);
+ struct device *dev = &rc->uwb_dev.dev;
+
+ bow->can_reserve_extra_mases = true;
+ if (bow->total_expired <= 4) {
+ bow->total_expired++;
+ } else {
+ /* after 4 backoff window has expired we can exit from
+ * the backoff procedure */
+ bow->total_expired = 0;
+ bow->window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
+ }
+ dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n", bow->total_expired, bow->n);
+
+ /* try to relocate all the "to be moved" relocations */
+ uwb_rsv_handle_drp_avail_change(rc);
+}
+
+void uwb_rsv_backoff_win_increment(struct uwb_rc *rc)
+{
+ struct uwb_drp_backoff_win *bow = &rc->bow;
+ struct device *dev = &rc->uwb_dev.dev;
+ unsigned timeout_us;
+
+ dev_dbg(dev, "backoff_win_increment: window=%d\n", bow->window);
+
+ bow->can_reserve_extra_mases = false;
+
+ if((bow->window << 1) == UWB_DRP_BACKOFF_WIN_MAX)
+ return;
+
+ bow->window <<= 1;
+ bow->n = prandom_u32() & (bow->window - 1);
+ dev_dbg(dev, "new_window=%d, n=%d\n", bow->window, bow->n);
+
+ /* reset the timer associated variables */
+ timeout_us = bow->n * UWB_SUPERFRAME_LENGTH_US;
+ bow->total_expired = 0;
+ mod_timer(&bow->timer, jiffies + usecs_to_jiffies(timeout_us));
+}
+
+static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv)
+{
+ int sframes = UWB_MAX_LOST_BEACONS;
+
+ /*
+ * Multicast reservations can become established within 1
+ * super frame and should not be terminated if no response is
+ * received.
+ */
+ if (rsv->state == UWB_RSV_STATE_NONE) {
+ sframes = 0;
+ } else if (rsv->is_multicast) {
+ if (rsv->state == UWB_RSV_STATE_O_INITIATED
+ || rsv->state == UWB_RSV_STATE_O_MOVE_EXPANDING
+ || rsv->state == UWB_RSV_STATE_O_MOVE_COMBINING
+ || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING)
+ sframes = 1;
+ if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED)
+ sframes = 0;
+
+ }
+
+ if (sframes > 0) {
+ /*
+ * Add an additional 2 superframes to account for the
+ * time to send the SET DRP IE command.
+ */
+ unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US;
+ mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us));
+ } else
+ del_timer(&rsv->timer);
+}
+
+/*
+ * Update a reservations state, and schedule an update of the
+ * transmitted DRP IEs.
+ */
+static void uwb_rsv_state_update(struct uwb_rsv *rsv,
+ enum uwb_rsv_state new_state)
+{
+ rsv->state = new_state;
+ rsv->ie_valid = false;
+
+ uwb_rsv_dump("SU", rsv);
+
+ uwb_rsv_stroke_timer(rsv);
+ uwb_rsv_sched_update(rsv->rc);
+}
+
+static void uwb_rsv_callback(struct uwb_rsv *rsv)
+{
+ if (rsv->callback)
+ rsv->callback(rsv);
+}
+
+void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state)
+{
+ struct uwb_rsv_move *mv = &rsv->mv;
+
+ if (rsv->state == new_state) {
+ switch (rsv->state) {
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ case UWB_RSV_STATE_O_MOVE_EXPANDING:
+ case UWB_RSV_STATE_O_MOVE_COMBINING:
+ case UWB_RSV_STATE_O_MOVE_REDUCING:
+ case UWB_RSV_STATE_T_ACCEPTED:
+ case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
+ case UWB_RSV_STATE_T_RESIZED:
+ case UWB_RSV_STATE_NONE:
+ uwb_rsv_stroke_timer(rsv);
+ break;
+ default:
+ /* Expecting a state transition so leave timer
+ as-is. */
+ break;
+ }
+ return;
+ }
+
+ uwb_rsv_dump("SC", rsv);
+
+ switch (new_state) {
+ case UWB_RSV_STATE_NONE:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE);
+ uwb_rsv_remove(rsv);
+ uwb_rsv_callback(rsv);
+ break;
+ case UWB_RSV_STATE_O_INITIATED:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED);
+ break;
+ case UWB_RSV_STATE_O_PENDING:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING);
+ break;
+ case UWB_RSV_STATE_O_MODIFIED:
+ /* in the companion there are the MASes to drop */
+ bitmap_andnot(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS);
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MODIFIED);
+ break;
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ if (rsv->state == UWB_RSV_STATE_O_MODIFIED
+ || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING) {
+ uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
+ rsv->needs_release_companion_mas = false;
+ }
+ uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ uwb_rsv_callback(rsv);
+ break;
+ case UWB_RSV_STATE_O_MOVE_EXPANDING:
+ rsv->needs_release_companion_mas = true;
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
+ break;
+ case UWB_RSV_STATE_O_MOVE_COMBINING:
+ rsv->needs_release_companion_mas = false;
+ uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas);
+ bitmap_or(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS);
+ rsv->mas.safe += mv->companion_mas.safe;
+ rsv->mas.unsafe += mv->companion_mas.unsafe;
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+ break;
+ case UWB_RSV_STATE_O_MOVE_REDUCING:
+ bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS);
+ rsv->needs_release_companion_mas = true;
+ rsv->mas.safe = mv->final_mas.safe;
+ rsv->mas.unsafe = mv->final_mas.unsafe;
+ bitmap_copy(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS);
+ bitmap_copy(rsv->mas.unsafe_bm, mv->final_mas.unsafe_bm, UWB_NUM_MAS);
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+ break;
+ case UWB_RSV_STATE_T_ACCEPTED:
+ case UWB_RSV_STATE_T_RESIZED:
+ rsv->needs_release_companion_mas = false;
+ uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED);
+ uwb_rsv_callback(rsv);
+ break;
+ case UWB_RSV_STATE_T_DENIED:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED);
+ break;
+ case UWB_RSV_STATE_T_CONFLICT:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_CONFLICT);
+ break;
+ case UWB_RSV_STATE_T_PENDING:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_PENDING);
+ break;
+ case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
+ rsv->needs_release_companion_mas = true;
+ uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas);
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
+ break;
+ default:
+ dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n",
+ uwb_rsv_state_str(new_state), new_state);
+ }
+}
+
+static void uwb_rsv_handle_timeout_work(struct work_struct *work)
+{
+ struct uwb_rsv *rsv = container_of(work, struct uwb_rsv,
+ handle_timeout_work);
+ struct uwb_rc *rc = rsv->rc;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ uwb_rsv_dump("TO", rsv);
+
+ switch (rsv->state) {
+ case UWB_RSV_STATE_O_INITIATED:
+ if (rsv->is_multicast) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ goto unlock;
+ }
+ break;
+ case UWB_RSV_STATE_O_MOVE_EXPANDING:
+ if (rsv->is_multicast) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+ goto unlock;
+ }
+ break;
+ case UWB_RSV_STATE_O_MOVE_COMBINING:
+ if (rsv->is_multicast) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+ goto unlock;
+ }
+ break;
+ case UWB_RSV_STATE_O_MOVE_REDUCING:
+ if (rsv->is_multicast) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ goto unlock;
+ }
+ break;
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ if (rsv->is_multicast)
+ goto unlock;
+ break;
+ case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
+ /*
+ * The time out could be for the main or of the
+ * companion DRP, assume it's for the companion and
+ * drop that first. A further time out is required to
+ * drop the main.
+ */
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
+ uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
+ goto unlock;
+ case UWB_RSV_STATE_NONE:
+ goto unlock;
+ default:
+ break;
+ }
+
+ uwb_rsv_remove(rsv);
+
+unlock:
+ mutex_unlock(&rc->rsvs_mutex);
+}
+
+static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
+{
+ struct uwb_rsv *rsv;
+
+ rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL);
+ if (!rsv)
+ return NULL;
+
+ INIT_LIST_HEAD(&rsv->rc_node);
+ INIT_LIST_HEAD(&rsv->pal_node);
+ kref_init(&rsv->kref);
+ timer_setup(&rsv->timer, uwb_rsv_timer, 0);
+
+ rsv->rc = rc;
+ INIT_WORK(&rsv->handle_timeout_work, uwb_rsv_handle_timeout_work);
+
+ return rsv;
+}
+
+/**
+ * uwb_rsv_create - allocate and initialize a UWB reservation structure
+ * @rc: the radio controller
+ * @cb: callback to use when the reservation completes or terminates
+ * @pal_priv: data private to the PAL to be passed in the callback
+ *
+ * The callback is called when the state of the reservation changes from:
+ *
+ * - pending to accepted
+ * - pending to denined
+ * - accepted to terminated
+ * - pending to terminated
+ */
+struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv)
+{
+ struct uwb_rsv *rsv;
+
+ rsv = uwb_rsv_alloc(rc);
+ if (!rsv)
+ return NULL;
+
+ rsv->callback = cb;
+ rsv->pal_priv = pal_priv;
+
+ return rsv;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_create);
+
+void uwb_rsv_remove(struct uwb_rsv *rsv)
+{
+ uwb_rsv_dump("RM", rsv);
+
+ if (rsv->state != UWB_RSV_STATE_NONE)
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+
+ if (rsv->needs_release_companion_mas)
+ uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
+ uwb_drp_avail_release(rsv->rc, &rsv->mas);
+
+ if (uwb_rsv_is_owner(rsv))
+ uwb_rsv_put_stream(rsv);
+
+ uwb_dev_put(rsv->owner);
+ if (rsv->target.type == UWB_RSV_TARGET_DEV)
+ uwb_dev_put(rsv->target.dev);
+
+ list_del_init(&rsv->rc_node);
+ uwb_rsv_put(rsv);
+}
+
+/**
+ * uwb_rsv_destroy - free a UWB reservation structure
+ * @rsv: the reservation to free
+ *
+ * The reservation must already be terminated.
+ */
+void uwb_rsv_destroy(struct uwb_rsv *rsv)
+{
+ uwb_rsv_put(rsv);
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
+
+/**
+ * usb_rsv_establish - start a reservation establishment
+ * @rsv: the reservation
+ *
+ * The PAL should fill in @rsv's owner, target, type, max_mas,
+ * min_mas, max_interval and is_multicast fields. If the target is a
+ * uwb_dev it must be referenced.
+ *
+ * The reservation's callback will be called when the reservation is
+ * accepted, denied or times out.
+ */
+int uwb_rsv_establish(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+ struct uwb_mas_bm available;
+ struct device *dev = &rc->uwb_dev.dev;
+ int ret;
+
+ mutex_lock(&rc->rsvs_mutex);
+ ret = uwb_rsv_get_stream(rsv);
+ if (ret) {
+ dev_err(dev, "%s: uwb_rsv_get_stream failed: %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ rsv->tiebreaker = prandom_u32() & 1;
+ /* get available mas bitmap */
+ uwb_drp_available(rc, &available);
+
+ ret = uwb_rsv_find_best_allocation(rsv, &available, &rsv->mas);
+ if (ret == UWB_RSV_ALLOC_NOT_FOUND) {
+ ret = -EBUSY;
+ uwb_rsv_put_stream(rsv);
+ dev_err(dev, "%s: uwb_rsv_find_best_allocation failed: %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ ret = uwb_drp_avail_reserve_pending(rc, &rsv->mas);
+ if (ret != 0) {
+ uwb_rsv_put_stream(rsv);
+ dev_err(dev, "%s: uwb_drp_avail_reserve_pending failed: %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ uwb_rsv_get(rsv);
+ list_add_tail(&rsv->rc_node, &rc->reservations);
+ rsv->owner = &rc->uwb_dev;
+ uwb_dev_get(rsv->owner);
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED);
+out:
+ mutex_unlock(&rc->rsvs_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_establish);
+
+/**
+ * uwb_rsv_modify - modify an already established reservation
+ * @rsv: the reservation to modify
+ * @max_mas: new maximum MAS to reserve
+ * @min_mas: new minimum MAS to reserve
+ * @max_interval: new max_interval to use
+ *
+ * FIXME: implement this once there are PALs that use it.
+ */
+int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int max_interval)
+{
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_modify);
+
+/*
+ * move an already established reservation (rc->rsvs_mutex must to be
+ * taken when tis function is called)
+ */
+int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available)
+{
+ struct uwb_rc *rc = rsv->rc;
+ struct uwb_drp_backoff_win *bow = &rc->bow;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rsv_move *mv;
+ int ret = 0;
+
+ if (bow->can_reserve_extra_mases == false)
+ return -EBUSY;
+
+ mv = &rsv->mv;
+
+ if (uwb_rsv_find_best_allocation(rsv, available, &mv->final_mas) == UWB_RSV_ALLOC_FOUND) {
+
+ if (!bitmap_equal(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS)) {
+ /* We want to move the reservation */
+ bitmap_andnot(mv->companion_mas.bm, mv->final_mas.bm, rsv->mas.bm, UWB_NUM_MAS);
+ uwb_drp_avail_reserve_pending(rc, &mv->companion_mas);
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
+ }
+ } else {
+ dev_dbg(dev, "new allocation not found\n");
+ }
+
+ return ret;
+}
+
+/* It will try to move every reservation in state O_ESTABLISHED giving
+ * to the MAS allocator algorithm an availability that is the real one
+ * plus the allocation already established from the reservation. */
+void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc)
+{
+ struct uwb_drp_backoff_win *bow = &rc->bow;
+ struct uwb_rsv *rsv;
+ struct uwb_mas_bm mas;
+
+ if (bow->can_reserve_extra_mases == false)
+ return;
+
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED ||
+ rsv->state == UWB_RSV_STATE_O_TO_BE_MOVED) {
+ uwb_drp_available(rc, &mas);
+ bitmap_or(mas.bm, mas.bm, rsv->mas.bm, UWB_NUM_MAS);
+ uwb_rsv_try_move(rsv, &mas);
+ }
+ }
+
+}
+
+/**
+ * uwb_rsv_terminate - terminate an established reservation
+ * @rsv: the reservation to terminate
+ *
+ * A reservation is terminated by removing the DRP IE from the beacon,
+ * the other end will consider the reservation to be terminated when
+ * it does not see the DRP IE for at least mMaxLostBeacons.
+ *
+ * If applicable, the reference to the target uwb_dev will be released.
+ */
+void uwb_rsv_terminate(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ if (rsv->state != UWB_RSV_STATE_NONE)
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+
+ mutex_unlock(&rc->rsvs_mutex);
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_terminate);
+
+/**
+ * uwb_rsv_accept - accept a new reservation from a peer
+ * @rsv: the reservation
+ * @cb: call back for reservation changes
+ * @pal_priv: data to be passed in the above call back
+ *
+ * Reservation requests from peers are denied unless a PAL accepts it
+ * by calling this function.
+ *
+ * The PAL call uwb_rsv_destroy() for all accepted reservations before
+ * calling uwb_pal_unregister().
+ */
+void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv)
+{
+ uwb_rsv_get(rsv);
+
+ rsv->callback = cb;
+ rsv->pal_priv = pal_priv;
+ rsv->state = UWB_RSV_STATE_T_ACCEPTED;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_accept);
+
+/*
+ * Is a received DRP IE for this reservation?
+ */
+static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_dev_addr *rsv_src;
+ int stream;
+
+ stream = uwb_ie_drp_stream_index(drp_ie);
+
+ if (rsv->stream != stream)
+ return false;
+
+ switch (rsv->target.type) {
+ case UWB_RSV_TARGET_DEVADDR:
+ return rsv->stream == stream;
+ case UWB_RSV_TARGET_DEV:
+ if (uwb_ie_drp_owner(drp_ie))
+ rsv_src = &rsv->owner->dev_addr;
+ else
+ rsv_src = &rsv->target.dev->dev_addr;
+ return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0;
+ }
+ return false;
+}
+
+static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc,
+ struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_rsv *rsv;
+ struct uwb_pal *pal;
+ enum uwb_rsv_state state;
+
+ rsv = uwb_rsv_alloc(rc);
+ if (!rsv)
+ return NULL;
+
+ rsv->rc = rc;
+ rsv->owner = src;
+ uwb_dev_get(rsv->owner);
+ rsv->target.type = UWB_RSV_TARGET_DEV;
+ rsv->target.dev = &rc->uwb_dev;
+ uwb_dev_get(&rc->uwb_dev);
+ rsv->type = uwb_ie_drp_type(drp_ie);
+ rsv->stream = uwb_ie_drp_stream_index(drp_ie);
+ uwb_drp_ie_to_bm(&rsv->mas, drp_ie);
+
+ /*
+ * See if any PALs are interested in this reservation. If not,
+ * deny the request.
+ */
+ rsv->state = UWB_RSV_STATE_T_DENIED;
+ mutex_lock(&rc->uwb_dev.mutex);
+ list_for_each_entry(pal, &rc->pals, node) {
+ if (pal->new_rsv)
+ pal->new_rsv(pal, rsv);
+ if (rsv->state == UWB_RSV_STATE_T_ACCEPTED)
+ break;
+ }
+ mutex_unlock(&rc->uwb_dev.mutex);
+
+ list_add_tail(&rsv->rc_node, &rc->reservations);
+ state = rsv->state;
+ rsv->state = UWB_RSV_STATE_NONE;
+
+ /* FIXME: do something sensible here */
+ if (state == UWB_RSV_STATE_T_ACCEPTED
+ && uwb_drp_avail_reserve_pending(rc, &rsv->mas) == -EBUSY) {
+ /* FIXME: do something sensible here */
+ } else {
+ uwb_rsv_set_state(rsv, state);
+ }
+
+ return rsv;
+}
+
+/**
+ * uwb_rsv_get_usable_mas - get the bitmap of the usable MAS of a reservations
+ * @rsv: the reservation.
+ * @mas: returns the available MAS.
+ *
+ * The usable MAS of a reservation may be less than the negotiated MAS
+ * if alien BPs are present.
+ */
+void uwb_rsv_get_usable_mas(struct uwb_rsv *rsv, struct uwb_mas_bm *mas)
+{
+ bitmap_zero(mas->bm, UWB_NUM_MAS);
+ bitmap_andnot(mas->bm, rsv->mas.bm, rsv->rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_get_usable_mas);
+
+/**
+ * uwb_rsv_find - find a reservation for a received DRP IE.
+ * @rc: the radio controller
+ * @src: source of the DRP IE
+ * @drp_ie: the DRP IE
+ *
+ * If the reservation cannot be found and the DRP IE is from a peer
+ * attempting to establish a new reservation, create a new reservation
+ * and add it to the list.
+ */
+struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_rsv *rsv;
+
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (uwb_rsv_match(rsv, src, drp_ie))
+ return rsv;
+ }
+
+ if (uwb_ie_drp_owner(drp_ie))
+ return uwb_rsv_new_target(rc, src, drp_ie);
+
+ return NULL;
+}
+
+/*
+ * Go through all the reservations and check for timeouts and (if
+ * necessary) update their DRP IEs.
+ *
+ * FIXME: look at building the SET_DRP_IE command here rather than
+ * having to rescan the list in uwb_rc_send_all_drp_ie().
+ */
+static bool uwb_rsv_update_all(struct uwb_rc *rc)
+{
+ struct uwb_rsv *rsv, *t;
+ bool ie_updated = false;
+
+ list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
+ if (!rsv->ie_valid) {
+ uwb_drp_ie_update(rsv);
+ ie_updated = true;
+ }
+ }
+
+ return ie_updated;
+}
+
+void uwb_rsv_queue_update(struct uwb_rc *rc)
+{
+ unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
+
+ queue_delayed_work(rc->rsv_workq, &rc->rsv_update_work, usecs_to_jiffies(delay_us));
+}
+
+/**
+ * uwb_rsv_sched_update - schedule an update of the DRP IEs
+ * @rc: the radio controller.
+ *
+ * To improve performance and ensure correctness with [ECMA-368] the
+ * number of SET-DRP-IE commands that are done are limited.
+ *
+ * DRP IEs update come from two sources: DRP events from the hardware
+ * which all occur at the beginning of the superframe ('syncronous'
+ * events) and reservation establishment/termination requests from
+ * PALs or timers ('asynchronous' events).
+ *
+ * A delayed work ensures that all the synchronous events result in
+ * one SET-DRP-IE command.
+ *
+ * Additional logic (the set_drp_ie_pending and rsv_updated_postponed
+ * flags) will prevent an asynchrous event starting a SET-DRP-IE
+ * command if one is currently awaiting a response.
+ *
+ * FIXME: this does leave a window where an asynchrous event can delay
+ * the SET-DRP-IE for a synchronous event by one superframe.
+ */
+void uwb_rsv_sched_update(struct uwb_rc *rc)
+{
+ spin_lock_irq(&rc->rsvs_lock);
+ if (!delayed_work_pending(&rc->rsv_update_work)) {
+ if (rc->set_drp_ie_pending > 0) {
+ rc->set_drp_ie_pending++;
+ goto unlock;
+ }
+ uwb_rsv_queue_update(rc);
+ }
+unlock:
+ spin_unlock_irq(&rc->rsvs_lock);
+}
+
+/*
+ * Update DRP IEs and, if necessary, the DRP Availability IE and send
+ * the updated IEs to the radio controller.
+ */
+static void uwb_rsv_update_work(struct work_struct *work)
+{
+ struct uwb_rc *rc = container_of(work, struct uwb_rc,
+ rsv_update_work.work);
+ bool ie_updated;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ ie_updated = uwb_rsv_update_all(rc);
+
+ if (!rc->drp_avail.ie_valid) {
+ uwb_drp_avail_ie_update(rc);
+ ie_updated = true;
+ }
+
+ if (ie_updated && (rc->set_drp_ie_pending == 0))
+ uwb_rc_send_all_drp_ie(rc);
+
+ mutex_unlock(&rc->rsvs_mutex);
+}
+
+static void uwb_rsv_alien_bp_work(struct work_struct *work)
+{
+ struct uwb_rc *rc = container_of(work, struct uwb_rc,
+ rsv_alien_bp_work.work);
+ struct uwb_rsv *rsv;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (rsv->type != UWB_DRP_TYPE_ALIEN_BP) {
+ uwb_rsv_callback(rsv);
+ }
+ }
+
+ mutex_unlock(&rc->rsvs_mutex);
+}
+
+static void uwb_rsv_timer(struct timer_list *t)
+{
+ struct uwb_rsv *rsv = from_timer(rsv, t, timer);
+
+ queue_work(rsv->rc->rsv_workq, &rsv->handle_timeout_work);
+}
+
+/**
+ * uwb_rsv_remove_all - remove all reservations
+ * @rc: the radio controller
+ *
+ * A DRP IE update is not done.
+ */
+void uwb_rsv_remove_all(struct uwb_rc *rc)
+{
+ struct uwb_rsv *rsv, *t;
+
+ mutex_lock(&rc->rsvs_mutex);
+ list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
+ if (rsv->state != UWB_RSV_STATE_NONE)
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+ del_timer_sync(&rsv->timer);
+ }
+ /* Cancel any postponed update. */
+ rc->set_drp_ie_pending = 0;
+ mutex_unlock(&rc->rsvs_mutex);
+
+ cancel_delayed_work_sync(&rc->rsv_update_work);
+ flush_workqueue(rc->rsv_workq);
+
+ mutex_lock(&rc->rsvs_mutex);
+ list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
+ uwb_rsv_remove(rsv);
+ }
+ mutex_unlock(&rc->rsvs_mutex);
+}
+
+void uwb_rsv_init(struct uwb_rc *rc)
+{
+ INIT_LIST_HEAD(&rc->reservations);
+ INIT_LIST_HEAD(&rc->cnflt_alien_list);
+ mutex_init(&rc->rsvs_mutex);
+ spin_lock_init(&rc->rsvs_lock);
+ INIT_DELAYED_WORK(&rc->rsv_update_work, uwb_rsv_update_work);
+ INIT_DELAYED_WORK(&rc->rsv_alien_bp_work, uwb_rsv_alien_bp_work);
+ rc->bow.can_reserve_extra_mases = true;
+ rc->bow.total_expired = 0;
+ rc->bow.window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
+ timer_setup(&rc->bow.timer, uwb_rsv_backoff_win_timer, 0);
+
+ bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS);
+}
+
+int uwb_rsv_setup(struct uwb_rc *rc)
+{
+ char name[16];
+
+ snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev));
+ rc->rsv_workq = create_singlethread_workqueue(name);
+ if (rc->rsv_workq == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void uwb_rsv_cleanup(struct uwb_rc *rc)
+{
+ uwb_rsv_remove_all(rc);
+ destroy_workqueue(rc->rsv_workq);
+}
diff --git a/drivers/staging/uwb/scan.c b/drivers/staging/uwb/scan.c
new file mode 100644
index 000000000000..ffc3f452302d
--- /dev/null
+++ b/drivers/staging/uwb/scan.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Scanning management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ * FIXME: there are issues here on how BEACON and SCAN on USB RCI deal
+ * with each other. Currently seems that START_BEACON while
+ * SCAN_ONLY will cancel the scan, so we need to update the
+ * state here. Clarification request sent by email on
+ * 10/05/2005.
+ * 10/28/2005 No clear answer heard--maybe we'll hack the API
+ * so that when we start beaconing, if the HC is
+ * scanning in a mode not compatible with beaconing
+ * we just fail.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include "uwb-internal.h"
+
+
+/**
+ * Start/stop scanning in a radio controller
+ *
+ * @rc: UWB Radio Controller
+ * @channel: Channel to scan; encodings in WUSB1.0[Table 5.12]
+ * @type: Type of scanning to do.
+ * @bpst_offset: value at which to start scanning (if type ==
+ * UWB_SCAN_ONLY_STARTTIME)
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ */
+int uwb_rc_scan(struct uwb_rc *rc,
+ unsigned channel, enum uwb_scan_type type,
+ unsigned bpst_offset)
+{
+ int result;
+ struct uwb_rc_cmd_scan *cmd;
+ struct uwb_rc_evt_confirm reply;
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_kzalloc;
+ mutex_lock(&rc->uwb_dev.mutex);
+ cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SCAN);
+ cmd->bChannelNumber = channel;
+ cmd->bScanState = type;
+ cmd->wStartTime = cpu_to_le16(bpst_offset);
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_SCAN;
+ result = uwb_rc_cmd(rc, "SCAN", &cmd->rccb, sizeof(*cmd),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "SCAN: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ goto error_cmd;
+ }
+ rc->scanning = channel;
+ rc->scan_type = type;
+error_cmd:
+ mutex_unlock(&rc->uwb_dev.mutex);
+ kfree(cmd);
+error_kzalloc:
+ return result;
+}
+
+/*
+ * Print scanning state
+ */
+static ssize_t uwb_rc_scan_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ ssize_t result;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = sprintf(buf, "%d %d\n", rc->scanning, rc->scan_type);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+/*
+ *
+ */
+static ssize_t uwb_rc_scan_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ unsigned channel;
+ unsigned type;
+ unsigned bpst_offset = 0;
+ ssize_t result = -EINVAL;
+
+ result = sscanf(buf, "%u %u %u\n", &channel, &type, &bpst_offset);
+ if (result >= 2 && type < UWB_SCAN_TOP)
+ result = uwb_rc_scan(rc, channel, type, bpst_offset);
+
+ return result < 0 ? result : size;
+}
+
+/** Radio Control sysfs interface (declaration) */
+DEVICE_ATTR(scan, S_IRUGO | S_IWUSR, uwb_rc_scan_show, uwb_rc_scan_store);
diff --git a/drivers/staging/uwb/umc-bus.c b/drivers/staging/uwb/umc-bus.c
new file mode 100644
index 000000000000..8b931f66a720
--- /dev/null
+++ b/drivers/staging/uwb/umc-bus.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Bus for UWB Multi-interface Controller capabilities.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "include/umc.h"
+
+static int umc_bus_pre_reset_helper(struct device *dev, void *data)
+{
+ int ret = 0;
+
+ if (dev->driver) {
+ struct umc_dev *umc = to_umc_dev(dev);
+ struct umc_driver *umc_drv = to_umc_driver(dev->driver);
+
+ if (umc_drv->pre_reset)
+ ret = umc_drv->pre_reset(umc);
+ else
+ device_release_driver(dev);
+ }
+ return ret;
+}
+
+static int umc_bus_post_reset_helper(struct device *dev, void *data)
+{
+ int ret = 0;
+
+ if (dev->driver) {
+ struct umc_dev *umc = to_umc_dev(dev);
+ struct umc_driver *umc_drv = to_umc_driver(dev->driver);
+
+ if (umc_drv->post_reset)
+ ret = umc_drv->post_reset(umc);
+ } else
+ ret = device_attach(dev);
+
+ return ret;
+}
+
+/**
+ * umc_controller_reset - reset the whole UMC controller
+ * @umc: the UMC device for the radio controller.
+ *
+ * Drivers or all capabilities of the controller will have their
+ * pre_reset methods called or be unbound from their device. Then all
+ * post_reset methods will be called or the drivers will be rebound.
+ *
+ * Radio controllers must provide pre_reset and post_reset methods and
+ * reset the hardware in their start method.
+ *
+ * If this is called while a probe() or remove() is in progress it
+ * will return -EAGAIN and not perform the reset.
+ */
+int umc_controller_reset(struct umc_dev *umc)
+{
+ struct device *parent = umc->dev.parent;
+ int ret = 0;
+
+ if (!device_trylock(parent))
+ return -EAGAIN;
+ ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper);
+ if (ret >= 0)
+ ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper);
+ device_unlock(parent);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(umc_controller_reset);
+
+/**
+ * umc_match_pci_id - match a UMC driver to a UMC device's parent PCI device.
+ * @umc_drv: umc driver with match_data pointing to a zero-terminated
+ * table of pci_device_id's.
+ * @umc: umc device whose parent is to be matched.
+ */
+int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc)
+{
+ const struct pci_device_id *id_table = umc_drv->match_data;
+ struct pci_dev *pci;
+
+ if (!dev_is_pci(umc->dev.parent))
+ return 0;
+
+ pci = to_pci_dev(umc->dev.parent);
+ return pci_match_id(id_table, pci) != NULL;
+}
+EXPORT_SYMBOL_GPL(umc_match_pci_id);
+
+static int umc_bus_rescan_helper(struct device *dev, void *data)
+{
+ int ret = 0;
+
+ if (!dev->driver)
+ ret = device_attach(dev);
+
+ return ret;
+}
+
+static void umc_bus_rescan(struct device *parent)
+{
+ int err;
+
+ /*
+ * We can't use bus_rescan_devices() here as it deadlocks when
+ * it tries to retake the dev->parent semaphore.
+ */
+ err = device_for_each_child(parent, NULL, umc_bus_rescan_helper);
+ if (err < 0)
+ printk(KERN_WARNING "%s: rescan of bus failed: %d\n",
+ KBUILD_MODNAME, err);
+}
+
+static int umc_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct umc_dev *umc = to_umc_dev(dev);
+ struct umc_driver *umc_driver = to_umc_driver(drv);
+
+ if (umc->cap_id == umc_driver->cap_id) {
+ if (umc_driver->match)
+ return umc_driver->match(umc_driver, umc);
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int umc_device_probe(struct device *dev)
+{
+ struct umc_dev *umc;
+ struct umc_driver *umc_driver;
+ int err;
+
+ umc_driver = to_umc_driver(dev->driver);
+ umc = to_umc_dev(dev);
+
+ get_device(dev);
+ err = umc_driver->probe(umc);
+ if (err)
+ put_device(dev);
+ else
+ umc_bus_rescan(dev->parent);
+
+ return err;
+}
+
+static int umc_device_remove(struct device *dev)
+{
+ struct umc_dev *umc;
+ struct umc_driver *umc_driver;
+
+ umc_driver = to_umc_driver(dev->driver);
+ umc = to_umc_dev(dev);
+
+ umc_driver->remove(umc);
+ put_device(dev);
+ return 0;
+}
+
+static ssize_t capability_id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct umc_dev *umc = to_umc_dev(dev);
+
+ return sprintf(buf, "0x%02x\n", umc->cap_id);
+}
+static DEVICE_ATTR_RO(capability_id);
+
+static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct umc_dev *umc = to_umc_dev(dev);
+
+ return sprintf(buf, "0x%04x\n", umc->version);
+}
+static DEVICE_ATTR_RO(version);
+
+static struct attribute *umc_dev_attrs[] = {
+ &dev_attr_capability_id.attr,
+ &dev_attr_version.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(umc_dev);
+
+struct bus_type umc_bus_type = {
+ .name = "umc",
+ .match = umc_bus_match,
+ .probe = umc_device_probe,
+ .remove = umc_device_remove,
+ .dev_groups = umc_dev_groups,
+};
+EXPORT_SYMBOL_GPL(umc_bus_type);
+
+static int __init umc_bus_init(void)
+{
+ return bus_register(&umc_bus_type);
+}
+module_init(umc_bus_init);
+
+static void __exit umc_bus_exit(void)
+{
+ bus_unregister(&umc_bus_type);
+}
+module_exit(umc_bus_exit);
+
+MODULE_DESCRIPTION("UWB Multi-interface Controller capability bus");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/umc-dev.c b/drivers/staging/uwb/umc-dev.c
new file mode 100644
index 000000000000..0c71caae00be
--- /dev/null
+++ b/drivers/staging/uwb/umc-dev.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB Multi-interface Controller device management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include "include/umc.h"
+
+static void umc_device_release(struct device *dev)
+{
+ struct umc_dev *umc = to_umc_dev(dev);
+
+ kfree(umc);
+}
+
+/**
+ * umc_device_create - allocate a child UMC device
+ * @parent: parent of the new UMC device.
+ * @n: index of the new device.
+ *
+ * The new UMC device will have a bus ID of the parent with '-n'
+ * appended.
+ */
+struct umc_dev *umc_device_create(struct device *parent, int n)
+{
+ struct umc_dev *umc;
+
+ umc = kzalloc(sizeof(struct umc_dev), GFP_KERNEL);
+ if (umc) {
+ dev_set_name(&umc->dev, "%s-%d", dev_name(parent), n);
+ umc->dev.parent = parent;
+ umc->dev.bus = &umc_bus_type;
+ umc->dev.release = umc_device_release;
+
+ umc->dev.dma_mask = parent->dma_mask;
+ }
+ return umc;
+}
+EXPORT_SYMBOL_GPL(umc_device_create);
+
+/**
+ * umc_device_register - register a UMC device
+ * @umc: pointer to the UMC device
+ *
+ * The memory resource for the UMC device is acquired and the device
+ * registered with the system.
+ */
+int umc_device_register(struct umc_dev *umc)
+{
+ int err;
+
+ err = request_resource(umc->resource.parent, &umc->resource);
+ if (err < 0) {
+ dev_err(&umc->dev, "can't allocate resource range %pR: %d\n",
+ &umc->resource, err);
+ goto error_request_resource;
+ }
+
+ err = device_register(&umc->dev);
+ if (err < 0)
+ goto error_device_register;
+ return 0;
+
+error_device_register:
+ put_device(&umc->dev);
+ release_resource(&umc->resource);
+error_request_resource:
+ return err;
+}
+EXPORT_SYMBOL_GPL(umc_device_register);
+
+/**
+ * umc_device_unregister - unregister a UMC device
+ * @umc: pointer to the UMC device
+ *
+ * First we unregister the device, make sure the driver can do it's
+ * resource release thing and then we try to release any left over
+ * resources. We take a ref to the device, to make sure it doesn't
+ * disappear under our feet.
+ */
+void umc_device_unregister(struct umc_dev *umc)
+{
+ struct device *dev;
+ if (!umc)
+ return;
+ dev = get_device(&umc->dev);
+ device_unregister(&umc->dev);
+ release_resource(&umc->resource);
+ put_device(dev);
+}
+EXPORT_SYMBOL_GPL(umc_device_unregister);
diff --git a/drivers/staging/uwb/umc-drv.c b/drivers/staging/uwb/umc-drv.c
new file mode 100644
index 000000000000..ed3bd220e8c2
--- /dev/null
+++ b/drivers/staging/uwb/umc-drv.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB Multi-interface Controller driver management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include "include/umc.h"
+
+int __umc_driver_register(struct umc_driver *umc_drv, struct module *module,
+ const char *mod_name)
+{
+ umc_drv->driver.name = umc_drv->name;
+ umc_drv->driver.owner = module;
+ umc_drv->driver.mod_name = mod_name;
+ umc_drv->driver.bus = &umc_bus_type;
+
+ return driver_register(&umc_drv->driver);
+}
+EXPORT_SYMBOL_GPL(__umc_driver_register);
+
+/**
+ * umc_driver_register - unregister a UMC capabiltity driver.
+ * @umc_drv: pointer to the driver.
+ */
+void umc_driver_unregister(struct umc_driver *umc_drv)
+{
+ driver_unregister(&umc_drv->driver);
+}
+EXPORT_SYMBOL_GPL(umc_driver_unregister);
diff --git a/drivers/staging/uwb/uwb-debug.c b/drivers/staging/uwb/uwb-debug.c
new file mode 100644
index 000000000000..dd14df219ef8
--- /dev/null
+++ b/drivers/staging/uwb/uwb-debug.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Debug support
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * FIXME: doc
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+#include "include/debug-cmd.h"
+#include "uwb-internal.h"
+
+/*
+ * Debug interface
+ *
+ * Per radio controller debugfs files (in uwb/uwbN/):
+ *
+ * command: Flexible command interface (see <linux/uwb/debug-cmd.h>).
+ *
+ * reservations: information on reservations.
+ *
+ * accept: Set to true (Y or 1) to accept reservation requests from
+ * peers.
+ *
+ * drp_avail: DRP availability information.
+ */
+
+struct uwb_dbg {
+ struct uwb_pal pal;
+
+ bool accept;
+ struct list_head rsvs;
+
+ struct dentry *root_d;
+ struct dentry *command_f;
+ struct dentry *reservations_f;
+ struct dentry *accept_f;
+ struct dentry *drp_avail_f;
+ spinlock_t list_lock;
+};
+
+static struct dentry *root_dir;
+
+static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
+{
+ struct uwb_dbg *dbg = rsv->pal_priv;
+
+ uwb_rsv_dump("debug", rsv);
+
+ if (rsv->state == UWB_RSV_STATE_NONE) {
+ spin_lock(&dbg->list_lock);
+ list_del(&rsv->pal_node);
+ spin_unlock(&dbg->list_lock);
+ uwb_rsv_destroy(rsv);
+ }
+}
+
+static int cmd_rsv_establish(struct uwb_rc *rc,
+ struct uwb_dbg_cmd_rsv_establish *cmd)
+{
+ struct uwb_mac_addr macaddr;
+ struct uwb_rsv *rsv;
+ struct uwb_dev *target;
+ int ret;
+
+ memcpy(&macaddr, cmd->target, sizeof(macaddr));
+ target = uwb_dev_get_by_macaddr(rc, &macaddr);
+ if (target == NULL)
+ return -ENODEV;
+
+ rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg);
+ if (rsv == NULL) {
+ uwb_dev_put(target);
+ return -ENOMEM;
+ }
+
+ rsv->target.type = UWB_RSV_TARGET_DEV;
+ rsv->target.dev = target;
+ rsv->type = cmd->type;
+ rsv->max_mas = cmd->max_mas;
+ rsv->min_mas = cmd->min_mas;
+ rsv->max_interval = cmd->max_interval;
+
+ ret = uwb_rsv_establish(rsv);
+ if (ret)
+ uwb_rsv_destroy(rsv);
+ else {
+ spin_lock(&(rc->dbg)->list_lock);
+ list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
+ spin_unlock(&(rc->dbg)->list_lock);
+ }
+ return ret;
+}
+
+static int cmd_rsv_terminate(struct uwb_rc *rc,
+ struct uwb_dbg_cmd_rsv_terminate *cmd)
+{
+ struct uwb_rsv *rsv, *found = NULL;
+ int i = 0;
+
+ spin_lock(&(rc->dbg)->list_lock);
+
+ list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
+ if (i == cmd->index) {
+ found = rsv;
+ uwb_rsv_get(found);
+ break;
+ }
+ i++;
+ }
+
+ spin_unlock(&(rc->dbg)->list_lock);
+
+ if (!found)
+ return -EINVAL;
+
+ uwb_rsv_terminate(found);
+ uwb_rsv_put(found);
+
+ return 0;
+}
+
+static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add)
+{
+ return uwb_rc_ie_add(rc,
+ (const struct uwb_ie_hdr *) ie_to_add->data,
+ ie_to_add->len);
+}
+
+static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm)
+{
+ return uwb_rc_ie_rm(rc, ie_to_rm->data[0]);
+}
+
+static ssize_t command_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *off)
+{
+ struct uwb_rc *rc = file->private_data;
+ struct uwb_dbg_cmd cmd;
+ int ret = 0;
+
+ if (len != sizeof(struct uwb_dbg_cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd, buf, len) != 0)
+ return -EFAULT;
+
+ switch (cmd.type) {
+ case UWB_DBG_CMD_RSV_ESTABLISH:
+ ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
+ break;
+ case UWB_DBG_CMD_RSV_TERMINATE:
+ ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
+ break;
+ case UWB_DBG_CMD_IE_ADD:
+ ret = cmd_ie_add(rc, &cmd.ie_add);
+ break;
+ case UWB_DBG_CMD_IE_RM:
+ ret = cmd_ie_rm(rc, &cmd.ie_rm);
+ break;
+ case UWB_DBG_CMD_RADIO_START:
+ ret = uwb_radio_start(&rc->dbg->pal);
+ break;
+ case UWB_DBG_CMD_RADIO_STOP:
+ uwb_radio_stop(&rc->dbg->pal);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret < 0 ? ret : len;
+}
+
+static const struct file_operations command_fops = {
+ .open = simple_open,
+ .write = command_write,
+ .read = NULL,
+ .llseek = no_llseek,
+ .owner = THIS_MODULE,
+};
+
+static int reservations_show(struct seq_file *s, void *p)
+{
+ struct uwb_rc *rc = s->private;
+ struct uwb_rsv *rsv;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ struct uwb_dev_addr devaddr;
+ char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
+ bool is_owner;
+
+ uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
+ if (rsv->target.type == UWB_RSV_TARGET_DEV) {
+ devaddr = rsv->target.dev->dev_addr;
+ is_owner = &rc->uwb_dev == rsv->owner;
+ } else {
+ devaddr = rsv->target.devaddr;
+ is_owner = true;
+ }
+ uwb_dev_addr_print(target, sizeof(target), &devaddr);
+
+ seq_printf(s, "%c %s -> %s: %s\n",
+ is_owner ? 'O' : 'T',
+ owner, target, uwb_rsv_state_str(rsv->state));
+ seq_printf(s, " stream: %d type: %s\n",
+ rsv->stream, uwb_rsv_type_str(rsv->type));
+ seq_printf(s, " %*pb\n", UWB_NUM_MAS, rsv->mas.bm);
+ }
+
+ mutex_unlock(&rc->rsvs_mutex);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(reservations);
+
+static int drp_avail_show(struct seq_file *s, void *p)
+{
+ struct uwb_rc *rc = s->private;
+
+ seq_printf(s, "global: %*pb\n", UWB_NUM_MAS, rc->drp_avail.global);
+ seq_printf(s, "local: %*pb\n", UWB_NUM_MAS, rc->drp_avail.local);
+ seq_printf(s, "pending: %*pb\n", UWB_NUM_MAS, rc->drp_avail.pending);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(drp_avail);
+
+static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
+{
+ struct device *dev = &pal->rc->uwb_dev.dev;
+
+ if (channel > 0)
+ dev_info(dev, "debug: channel %d started\n", channel);
+ else
+ dev_info(dev, "debug: channel stopped\n");
+}
+
+static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
+{
+ struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
+
+ if (dbg->accept) {
+ spin_lock(&dbg->list_lock);
+ list_add_tail(&rsv->pal_node, &dbg->rsvs);
+ spin_unlock(&dbg->list_lock);
+ uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg);
+ }
+}
+
+/**
+ * uwb_dbg_add_rc - add a debug interface for a radio controller
+ * @rc: the radio controller
+ */
+void uwb_dbg_add_rc(struct uwb_rc *rc)
+{
+ rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
+ if (rc->dbg == NULL)
+ return;
+
+ INIT_LIST_HEAD(&rc->dbg->rsvs);
+ spin_lock_init(&(rc->dbg)->list_lock);
+
+ uwb_pal_init(&rc->dbg->pal);
+ rc->dbg->pal.rc = rc;
+ rc->dbg->pal.channel_changed = uwb_dbg_channel_changed;
+ rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
+ uwb_pal_register(&rc->dbg->pal);
+
+ if (root_dir) {
+ rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
+ root_dir);
+ rc->dbg->command_f = debugfs_create_file("command", 0200,
+ rc->dbg->root_d, rc,
+ &command_fops);
+ rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
+ rc->dbg->root_d, rc,
+ &reservations_fops);
+ rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
+ rc->dbg->root_d,
+ &rc->dbg->accept);
+ rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
+ rc->dbg->root_d, rc,
+ &drp_avail_fops);
+ }
+}
+
+/**
+ * uwb_dbg_del_rc - remove a radio controller's debug interface
+ * @rc: the radio controller
+ */
+void uwb_dbg_del_rc(struct uwb_rc *rc)
+{
+ struct uwb_rsv *rsv, *t;
+
+ if (rc->dbg == NULL)
+ return;
+
+ list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
+ uwb_rsv_terminate(rsv);
+ }
+
+ uwb_pal_unregister(&rc->dbg->pal);
+
+ if (root_dir) {
+ debugfs_remove(rc->dbg->drp_avail_f);
+ debugfs_remove(rc->dbg->accept_f);
+ debugfs_remove(rc->dbg->reservations_f);
+ debugfs_remove(rc->dbg->command_f);
+ debugfs_remove(rc->dbg->root_d);
+ }
+}
+
+/**
+ * uwb_dbg_exit - initialize the debug interface sub-module
+ */
+void uwb_dbg_init(void)
+{
+ root_dir = debugfs_create_dir("uwb", NULL);
+}
+
+/**
+ * uwb_dbg_exit - clean-up the debug interface sub-module
+ */
+void uwb_dbg_exit(void)
+{
+ debugfs_remove(root_dir);
+}
+
+/**
+ * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL
+ * @pal: The PAL.
+ */
+struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal)
+{
+ struct uwb_rc *rc = pal->rc;
+
+ if (root_dir && rc->dbg && rc->dbg->root_d && pal->name)
+ return debugfs_create_dir(pal->name, rc->dbg->root_d);
+ return NULL;
+}
diff --git a/drivers/staging/uwb/uwb-internal.h b/drivers/staging/uwb/uwb-internal.h
new file mode 100644
index 000000000000..4c2fdac7f610
--- /dev/null
+++ b/drivers/staging/uwb/uwb-internal.h
@@ -0,0 +1,366 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Ultra Wide Band
+ * UWB internal API
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This contains most of the internal API for UWB. This is stuff used
+ * across the stack that of course, is of no interest to the rest.
+ *
+ * Some parts might end up going public (like uwb_rc_*())...
+ */
+
+#ifndef __UWB_INTERNAL_H__
+#define __UWB_INTERNAL_H__
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include "uwb.h"
+
+struct uwb_beca_e;
+
+/* General device API */
+extern void uwb_dev_init(struct uwb_dev *uwb_dev);
+extern int __uwb_dev_offair(struct uwb_dev *, struct uwb_rc *);
+extern int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
+ struct uwb_rc *parent_rc);
+extern void uwb_dev_rm(struct uwb_dev *uwb_dev);
+extern void uwbd_dev_onair(struct uwb_rc *, struct uwb_beca_e *);
+extern void uwbd_dev_offair(struct uwb_beca_e *);
+void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event);
+
+/* General UWB Radio Controller Internal API */
+extern struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *);
+static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc)
+{
+ uwb_dev_get(&rc->uwb_dev);
+ return rc;
+}
+
+static inline void __uwb_rc_put(struct uwb_rc *rc)
+{
+ if (rc)
+ uwb_dev_put(&rc->uwb_dev);
+}
+
+extern int uwb_rc_reset(struct uwb_rc *rc);
+extern int uwb_rc_beacon(struct uwb_rc *rc,
+ int channel, unsigned bpst_offset);
+extern int uwb_rc_scan(struct uwb_rc *rc,
+ unsigned channel, enum uwb_scan_type type,
+ unsigned bpst_offset);
+extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc);
+
+void uwb_rc_ie_init(struct uwb_rc *);
+int uwb_rc_ie_setup(struct uwb_rc *);
+void uwb_rc_ie_release(struct uwb_rc *);
+int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len,
+ char *buf, size_t size);
+int uwb_rc_set_ie(struct uwb_rc *, struct uwb_rc_cmd_set_ie *);
+
+
+extern const char *uwb_rc_strerror(unsigned code);
+
+/*
+ * Time to wait for a response to an RC command.
+ *
+ * Some commands can take a long time to response. e.g., START_BEACON
+ * may scan for several superframes before joining an existing beacon
+ * group and this can take around 600 ms.
+ */
+#define UWB_RC_CMD_TIMEOUT_MS 1000 /* ms */
+
+/*
+ * Notification/Event Handlers
+ */
+
+struct uwb_rc_neh;
+
+extern int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ u8 expected_type, u16 expected_event,
+ uwb_rc_cmd_cb_f cb, void *arg);
+
+
+void uwb_rc_neh_create(struct uwb_rc *rc);
+void uwb_rc_neh_destroy(struct uwb_rc *rc);
+
+struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
+ u8 expected_type, u16 expected_event,
+ uwb_rc_cmd_cb_f cb, void *arg);
+void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
+void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
+void uwb_rc_neh_put(struct uwb_rc_neh *neh);
+
+/* Event size tables */
+extern int uwb_est_create(void);
+extern void uwb_est_destroy(void);
+
+/*
+ * UWB conflicting alien reservations
+ */
+struct uwb_cnflt_alien {
+ struct uwb_rc *rc;
+ struct list_head rc_node;
+ struct uwb_mas_bm mas;
+ struct timer_list timer;
+ struct work_struct cnflt_update_work;
+};
+
+enum uwb_uwb_rsv_alloc_result {
+ UWB_RSV_ALLOC_FOUND = 0,
+ UWB_RSV_ALLOC_NOT_FOUND,
+};
+
+enum uwb_rsv_mas_status {
+ UWB_RSV_MAS_NOT_AVAIL = 1,
+ UWB_RSV_MAS_SAFE,
+ UWB_RSV_MAS_UNSAFE,
+};
+
+struct uwb_rsv_col_set_info {
+ unsigned char start_col;
+ unsigned char interval;
+ unsigned char safe_mas_per_col;
+ unsigned char unsafe_mas_per_col;
+};
+
+struct uwb_rsv_col_info {
+ unsigned char max_avail_safe;
+ unsigned char max_avail_unsafe;
+ unsigned char highest_mas[UWB_MAS_PER_ZONE];
+ struct uwb_rsv_col_set_info csi;
+};
+
+struct uwb_rsv_row_info {
+ unsigned char avail[UWB_MAS_PER_ZONE];
+ unsigned char free_rows;
+ unsigned char used_rows;
+};
+
+/*
+ * UWB find allocation
+ */
+struct uwb_rsv_alloc_info {
+ unsigned char bm[UWB_MAS_PER_ZONE * UWB_NUM_ZONES];
+ struct uwb_rsv_col_info ci[UWB_NUM_ZONES];
+ struct uwb_rsv_row_info ri;
+ struct uwb_mas_bm *not_available;
+ struct uwb_mas_bm *result;
+ int min_mas;
+ int max_mas;
+ int max_interval;
+ int total_allocated_mases;
+ int safe_allocated_mases;
+ int unsafe_allocated_mases;
+ int interval;
+};
+
+int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv,
+ struct uwb_mas_bm *available,
+ struct uwb_mas_bm *result);
+void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc);
+/*
+ * UWB Events & management daemon
+ */
+
+/**
+ * enum uwb_event_type - types of UWB management daemon events
+ *
+ * The UWB management daemon (uwbd) can receive two types of events:
+ * UWB_EVT_TYPE_NOTIF - notification from the radio controller.
+ * UWB_EVT_TYPE_MSG - a simple message.
+ */
+enum uwb_event_type {
+ UWB_EVT_TYPE_NOTIF,
+ UWB_EVT_TYPE_MSG,
+};
+
+/**
+ * struct uwb_event_notif - an event for a radio controller notification
+ * @size: Size of the buffer (ie: Guaranteed to contain at least
+ * a full 'struct uwb_rceb')
+ * @rceb: Pointer to a kmalloced() event payload
+ */
+struct uwb_event_notif {
+ size_t size;
+ struct uwb_rceb *rceb;
+};
+
+/**
+ * enum uwb_event_message - an event for a message for asynchronous processing
+ *
+ * UWB_EVT_MSG_RESET - reset the radio controller and all PAL hardware.
+ */
+enum uwb_event_message {
+ UWB_EVT_MSG_RESET,
+};
+
+/**
+ * UWB Event
+ * @rc: Radio controller that emitted the event (referenced)
+ * @ts_jiffies: Timestamp, when was it received
+ * @type: This event's type.
+ */
+struct uwb_event {
+ struct list_head list_node;
+ struct uwb_rc *rc;
+ unsigned long ts_jiffies;
+ enum uwb_event_type type;
+ union {
+ struct uwb_event_notif notif;
+ enum uwb_event_message message;
+ };
+};
+
+extern void uwbd_start(struct uwb_rc *rc);
+extern void uwbd_stop(struct uwb_rc *rc);
+extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask);
+extern void uwbd_event_queue(struct uwb_event *);
+void uwbd_flush(struct uwb_rc *rc);
+
+/* UWB event handlers */
+extern int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *);
+extern int uwbd_evt_handle_rc_beacon(struct uwb_event *);
+extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *);
+extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *);
+extern int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *);
+extern int uwbd_evt_handle_rc_drp(struct uwb_event *);
+extern int uwbd_evt_handle_rc_drp_avail(struct uwb_event *);
+
+int uwbd_msg_handle_reset(struct uwb_event *evt);
+
+
+/*
+ * Address management
+ */
+int uwb_rc_dev_addr_assign(struct uwb_rc *rc);
+int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt);
+
+/*
+ * UWB Beacon Cache
+ *
+ * Each beacon we received is kept in a cache--when we receive that
+ * beacon consistently, that means there is a new device that we have
+ * to add to the system.
+ */
+
+extern unsigned long beacon_timeout_ms;
+
+/**
+ * Beacon cache entry
+ *
+ * @jiffies_refresh: last time a beacon was received that refreshed
+ * this cache entry.
+ * @uwb_dev: device connected to this beacon. This pointer is not
+ * safe, you need to get it with uwb_dev_try_get()
+ *
+ * @hits: how many time we have seen this beacon since last time we
+ * cleared it
+ */
+struct uwb_beca_e {
+ struct mutex mutex;
+ struct kref refcnt;
+ struct list_head node;
+ struct uwb_mac_addr *mac_addr;
+ struct uwb_dev_addr dev_addr;
+ u8 hits;
+ unsigned long ts_jiffies;
+ struct uwb_dev *uwb_dev;
+ struct uwb_rc_evt_beacon *be;
+ struct stats lqe_stats, rssi_stats; /* radio statistics */
+};
+struct uwb_beacon_frame;
+extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *,
+ char *, size_t);
+
+extern void uwb_bce_kfree(struct kref *_bce);
+static inline void uwb_bce_get(struct uwb_beca_e *bce)
+{
+ kref_get(&bce->refcnt);
+}
+static inline void uwb_bce_put(struct uwb_beca_e *bce)
+{
+ kref_put(&bce->refcnt, uwb_bce_kfree);
+}
+extern void uwb_beca_purge(struct uwb_rc *rc);
+extern void uwb_beca_release(struct uwb_rc *rc);
+
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+ const struct uwb_dev_addr *devaddr);
+struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
+ const struct uwb_mac_addr *macaddr);
+
+int uwb_radio_setup(struct uwb_rc *rc);
+void uwb_radio_reset_state(struct uwb_rc *rc);
+void uwb_radio_shutdown(struct uwb_rc *rc);
+int uwb_radio_force_channel(struct uwb_rc *rc, int channel);
+
+/* -- UWB Sysfs representation */
+extern struct class uwb_rc_class;
+extern struct bus_type uwb_bus_type;
+extern struct device_attribute dev_attr_mac_address;
+extern struct device_attribute dev_attr_beacon;
+extern struct device_attribute dev_attr_scan;
+
+/* -- DRP Bandwidth allocator: bandwidth allocations, reservations, DRP */
+void uwb_rsv_init(struct uwb_rc *rc);
+int uwb_rsv_setup(struct uwb_rc *rc);
+void uwb_rsv_cleanup(struct uwb_rc *rc);
+void uwb_rsv_remove_all(struct uwb_rc *rc);
+void uwb_rsv_get(struct uwb_rsv *rsv);
+void uwb_rsv_put(struct uwb_rsv *rsv);
+bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv);
+void uwb_rsv_dump(char *text, struct uwb_rsv *rsv);
+int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available);
+void uwb_rsv_backoff_win_timer(struct timer_list *t);
+void uwb_rsv_backoff_win_increment(struct uwb_rc *rc);
+int uwb_rsv_status(struct uwb_rsv *rsv);
+int uwb_rsv_companion_status(struct uwb_rsv *rsv);
+
+void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state);
+void uwb_rsv_remove(struct uwb_rsv *rsv);
+struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie);
+void uwb_rsv_sched_update(struct uwb_rc *rc);
+void uwb_rsv_queue_update(struct uwb_rc *rc);
+
+int uwb_drp_ie_update(struct uwb_rsv *rsv);
+void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie);
+
+void uwb_drp_avail_init(struct uwb_rc *rc);
+void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail);
+int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_ie_update(struct uwb_rc *rc);
+
+/* -- PAL support */
+void uwb_rc_pal_init(struct uwb_rc *rc);
+
+/* -- Misc */
+
+extern ssize_t uwb_mac_frame_hdr_print(char *, size_t,
+ const struct uwb_mac_frame_hdr *);
+
+/* -- Debug interface */
+void uwb_dbg_init(void);
+void uwb_dbg_exit(void);
+void uwb_dbg_add_rc(struct uwb_rc *rc);
+void uwb_dbg_del_rc(struct uwb_rc *rc);
+struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal);
+
+static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
+{
+ device_lock(&uwb_dev->dev);
+}
+
+static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev)
+{
+ device_unlock(&uwb_dev->dev);
+}
+
+#endif /* #ifndef __UWB_INTERNAL_H__ */
diff --git a/drivers/staging/uwb/uwb.h b/drivers/staging/uwb/uwb.h
new file mode 100644
index 000000000000..6a59706ba3a0
--- /dev/null
+++ b/drivers/staging/uwb/uwb.h
@@ -0,0 +1,817 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Ultra Wide Band
+ * UWB API
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: doc: overview of the API, different parts and pointers
+ */
+
+#ifndef __LINUX__UWB_H__
+#define __LINUX__UWB_H__
+
+#include <linux/limits.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <asm/page.h>
+#include "include/spec.h"
+
+struct uwb_dev;
+struct uwb_beca_e;
+struct uwb_rc;
+struct uwb_rsv;
+struct uwb_dbg;
+
+/**
+ * struct uwb_dev - a UWB Device
+ * @rc: UWB Radio Controller that discovered the device (kind of its
+ * parent).
+ * @bce: a beacon cache entry for this device; or NULL if the device
+ * is a local radio controller.
+ * @mac_addr: the EUI-48 address of this device.
+ * @dev_addr: the current DevAddr used by this device.
+ * @beacon_slot: the slot number the beacon is using.
+ * @streams: bitmap of streams allocated to reservations targeted at
+ * this device. For an RC, this is the streams allocated for
+ * reservations targeted at DevAddrs.
+ *
+ * A UWB device may either by a neighbor or part of a local radio
+ * controller.
+ */
+struct uwb_dev {
+ struct mutex mutex;
+ struct list_head list_node;
+ struct device dev;
+ struct uwb_rc *rc; /* radio controller */
+ struct uwb_beca_e *bce; /* Beacon Cache Entry */
+
+ struct uwb_mac_addr mac_addr;
+ struct uwb_dev_addr dev_addr;
+ int beacon_slot;
+ DECLARE_BITMAP(streams, UWB_NUM_STREAMS);
+ DECLARE_BITMAP(last_availability_bm, UWB_NUM_MAS);
+};
+#define to_uwb_dev(d) container_of(d, struct uwb_dev, dev)
+
+/**
+ * UWB HWA/WHCI Radio Control {Command|Event} Block context IDs
+ *
+ * RC[CE]Bs have a 'context ID' field that matches the command with
+ * the event received to confirm it.
+ *
+ * Maximum number of context IDs
+ */
+enum { UWB_RC_CTX_MAX = 256 };
+
+
+/** Notification chain head for UWB generated events to listeners */
+struct uwb_notifs_chain {
+ struct list_head list;
+ struct mutex mutex;
+};
+
+/* Beacon cache list */
+struct uwb_beca {
+ struct list_head list;
+ size_t entries;
+ struct mutex mutex;
+};
+
+/* Event handling thread. */
+struct uwbd {
+ int pid;
+ struct task_struct *task;
+ wait_queue_head_t wq;
+ struct list_head event_list;
+ spinlock_t event_list_lock;
+};
+
+/**
+ * struct uwb_mas_bm - a bitmap of all MAS in a superframe
+ * @bm: a bitmap of length #UWB_NUM_MAS
+ */
+struct uwb_mas_bm {
+ DECLARE_BITMAP(bm, UWB_NUM_MAS);
+ DECLARE_BITMAP(unsafe_bm, UWB_NUM_MAS);
+ int safe;
+ int unsafe;
+};
+
+/**
+ * uwb_rsv_state - UWB Reservation state.
+ *
+ * NONE - reservation is not active (no DRP IE being transmitted).
+ *
+ * Owner reservation states:
+ *
+ * INITIATED - owner has sent an initial DRP request.
+ * PENDING - target responded with pending Reason Code.
+ * MODIFIED - reservation manager is modifying an established
+ * reservation with a different MAS allocation.
+ * ESTABLISHED - the reservation has been successfully negotiated.
+ *
+ * Target reservation states:
+ *
+ * DENIED - request is denied.
+ * ACCEPTED - request is accepted.
+ * PENDING - PAL has yet to make a decision to whether to accept or
+ * deny.
+ *
+ * FIXME: further target states TBD.
+ */
+enum uwb_rsv_state {
+ UWB_RSV_STATE_NONE = 0,
+ UWB_RSV_STATE_O_INITIATED,
+ UWB_RSV_STATE_O_PENDING,
+ UWB_RSV_STATE_O_MODIFIED,
+ UWB_RSV_STATE_O_ESTABLISHED,
+ UWB_RSV_STATE_O_TO_BE_MOVED,
+ UWB_RSV_STATE_O_MOVE_EXPANDING,
+ UWB_RSV_STATE_O_MOVE_COMBINING,
+ UWB_RSV_STATE_O_MOVE_REDUCING,
+ UWB_RSV_STATE_T_ACCEPTED,
+ UWB_RSV_STATE_T_DENIED,
+ UWB_RSV_STATE_T_CONFLICT,
+ UWB_RSV_STATE_T_PENDING,
+ UWB_RSV_STATE_T_EXPANDING_ACCEPTED,
+ UWB_RSV_STATE_T_EXPANDING_CONFLICT,
+ UWB_RSV_STATE_T_EXPANDING_PENDING,
+ UWB_RSV_STATE_T_EXPANDING_DENIED,
+ UWB_RSV_STATE_T_RESIZED,
+
+ UWB_RSV_STATE_LAST,
+};
+
+enum uwb_rsv_target_type {
+ UWB_RSV_TARGET_DEV,
+ UWB_RSV_TARGET_DEVADDR,
+};
+
+/**
+ * struct uwb_rsv_target - the target of a reservation.
+ *
+ * Reservations unicast and targeted at a single device
+ * (UWB_RSV_TARGET_DEV); or (e.g., in the case of WUSB) targeted at a
+ * specific (private) DevAddr (UWB_RSV_TARGET_DEVADDR).
+ */
+struct uwb_rsv_target {
+ enum uwb_rsv_target_type type;
+ union {
+ struct uwb_dev *dev;
+ struct uwb_dev_addr devaddr;
+ };
+};
+
+struct uwb_rsv_move {
+ struct uwb_mas_bm final_mas;
+ struct uwb_ie_drp *companion_drp_ie;
+ struct uwb_mas_bm companion_mas;
+};
+
+/*
+ * Number of streams reserved for reservations targeted at DevAddrs.
+ */
+#define UWB_NUM_GLOBAL_STREAMS 1
+
+typedef void (*uwb_rsv_cb_f)(struct uwb_rsv *rsv);
+
+/**
+ * struct uwb_rsv - a DRP reservation
+ *
+ * Data structure management:
+ *
+ * @rc: the radio controller this reservation is for
+ * (as target or owner)
+ * @rc_node: a list node for the RC
+ * @pal_node: a list node for the PAL
+ *
+ * Owner and target parameters:
+ *
+ * @owner: the UWB device owning this reservation
+ * @target: the target UWB device
+ * @type: reservation type
+ *
+ * Owner parameters:
+ *
+ * @max_mas: maxiumum number of MAS
+ * @min_mas: minimum number of MAS
+ * @sparsity: owner selected sparsity
+ * @is_multicast: true iff multicast
+ *
+ * @callback: callback function when the reservation completes
+ * @pal_priv: private data for the PAL making the reservation
+ *
+ * Reservation status:
+ *
+ * @status: negotiation status
+ * @stream: stream index allocated for this reservation
+ * @tiebreaker: conflict tiebreaker for this reservation
+ * @mas: reserved MAS
+ * @drp_ie: the DRP IE
+ * @ie_valid: true iff the DRP IE matches the reservation parameters
+ *
+ * DRP reservations are uniquely identified by the owner, target and
+ * stream index. However, when using a DevAddr as a target (e.g., for
+ * a WUSB cluster reservation) the responses may be received from
+ * devices with different DevAddrs. In this case, reservations are
+ * uniquely identified by just the stream index. A number of stream
+ * indexes (UWB_NUM_GLOBAL_STREAMS) are reserved for this.
+ */
+struct uwb_rsv {
+ struct uwb_rc *rc;
+ struct list_head rc_node;
+ struct list_head pal_node;
+ struct kref kref;
+
+ struct uwb_dev *owner;
+ struct uwb_rsv_target target;
+ enum uwb_drp_type type;
+ int max_mas;
+ int min_mas;
+ int max_interval;
+ bool is_multicast;
+
+ uwb_rsv_cb_f callback;
+ void *pal_priv;
+
+ enum uwb_rsv_state state;
+ bool needs_release_companion_mas;
+ u8 stream;
+ u8 tiebreaker;
+ struct uwb_mas_bm mas;
+ struct uwb_ie_drp *drp_ie;
+ struct uwb_rsv_move mv;
+ bool ie_valid;
+ struct timer_list timer;
+ struct work_struct handle_timeout_work;
+};
+
+static const
+struct uwb_mas_bm uwb_mas_bm_zero = { .bm = { 0 } };
+
+static inline void uwb_mas_bm_copy_le(void *dst, const struct uwb_mas_bm *mas)
+{
+ bitmap_copy_le(dst, mas->bm, UWB_NUM_MAS);
+}
+
+/**
+ * struct uwb_drp_avail - a radio controller's view of MAS usage
+ * @global: MAS unused by neighbors (excluding reservations targeted
+ * or owned by the local radio controller) or the beaon period
+ * @local: MAS unused by local established reservations
+ * @pending: MAS unused by local pending reservations
+ * @ie: DRP Availability IE to be included in the beacon
+ * @ie_valid: true iff @ie is valid and does not need to regenerated from
+ * @global and @local
+ *
+ * Each radio controller maintains a view of MAS usage or
+ * availability. MAS available for a new reservation are determined
+ * from the intersection of @global, @local, and @pending.
+ *
+ * The radio controller must transmit a DRP Availability IE that's the
+ * intersection of @global and @local.
+ *
+ * A set bit indicates the MAS is unused and available.
+ *
+ * rc->rsvs_mutex should be held before accessing this data structure.
+ *
+ * [ECMA-368] section 17.4.3.
+ */
+struct uwb_drp_avail {
+ DECLARE_BITMAP(global, UWB_NUM_MAS);
+ DECLARE_BITMAP(local, UWB_NUM_MAS);
+ DECLARE_BITMAP(pending, UWB_NUM_MAS);
+ struct uwb_ie_drp_avail ie;
+ bool ie_valid;
+};
+
+struct uwb_drp_backoff_win {
+ u8 window;
+ u8 n;
+ int total_expired;
+ struct timer_list timer;
+ bool can_reserve_extra_mases;
+};
+
+const char *uwb_rsv_state_str(enum uwb_rsv_state state);
+const char *uwb_rsv_type_str(enum uwb_drp_type type);
+
+struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb,
+ void *pal_priv);
+void uwb_rsv_destroy(struct uwb_rsv *rsv);
+
+int uwb_rsv_establish(struct uwb_rsv *rsv);
+int uwb_rsv_modify(struct uwb_rsv *rsv,
+ int max_mas, int min_mas, int sparsity);
+void uwb_rsv_terminate(struct uwb_rsv *rsv);
+
+void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv);
+
+void uwb_rsv_get_usable_mas(struct uwb_rsv *orig_rsv, struct uwb_mas_bm *mas);
+
+/**
+ * Radio Control Interface instance
+ *
+ *
+ * Life cycle rules: those of the UWB Device.
+ *
+ * @index: an index number for this radio controller, as used in the
+ * device name.
+ * @version: version of protocol supported by this device
+ * @priv: Backend implementation; rw with uwb_dev.dev.sem taken.
+ * @cmd: Backend implementation to execute commands; rw and call
+ * only with uwb_dev.dev.sem taken.
+ * @reset: Hardware reset of radio controller and any PAL controllers.
+ * @filter: Backend implementation to manipulate data to and from device
+ * to be compliant to specification assumed by driver (WHCI
+ * 0.95).
+ *
+ * uwb_dev.dev.mutex is used to execute commands and update
+ * the corresponding structures; can't use a spinlock
+ * because rc->cmd() can sleep.
+ * @ies: This is a dynamically allocated array cacheing the
+ * IEs (settable by the host) that the beacon of this
+ * radio controller is currently sending.
+ *
+ * In reality, we store here the full command we set to
+ * the radio controller (which is basically a command
+ * prefix followed by all the IEs the beacon currently
+ * contains). This way we don't have to realloc and
+ * memcpy when setting it.
+ *
+ * We set this up in uwb_rc_ie_setup(), where we alloc
+ * this struct, call get_ie() [so we know which IEs are
+ * currently being sent, if any].
+ *
+ * @ies_capacity:Amount of space (in bytes) allocated in @ies. The
+ * amount used is given by sizeof(*ies) plus ies->wIELength
+ * (which is a little endian quantity all the time).
+ * @ies_mutex: protect the IE cache
+ * @dbg: information for the debug interface
+ */
+struct uwb_rc {
+ struct uwb_dev uwb_dev;
+ int index;
+ u16 version;
+
+ struct module *owner;
+ void *priv;
+ int (*start)(struct uwb_rc *rc);
+ void (*stop)(struct uwb_rc *rc);
+ int (*cmd)(struct uwb_rc *, const struct uwb_rccb *, size_t);
+ int (*reset)(struct uwb_rc *rc);
+ int (*filter_cmd)(struct uwb_rc *, struct uwb_rccb **, size_t *);
+ int (*filter_event)(struct uwb_rc *, struct uwb_rceb **, const size_t,
+ size_t *, size_t *);
+
+ spinlock_t neh_lock; /* protects neh_* and ctx_* */
+ struct list_head neh_list; /* Open NE handles */
+ unsigned long ctx_bm[UWB_RC_CTX_MAX / 8 / sizeof(unsigned long)];
+ u8 ctx_roll;
+
+ int beaconing; /* Beaconing state [channel number] */
+ int beaconing_forced;
+ int scanning;
+ enum uwb_scan_type scan_type:3;
+ unsigned ready:1;
+ struct uwb_notifs_chain notifs_chain;
+ struct uwb_beca uwb_beca;
+
+ struct uwbd uwbd;
+
+ struct uwb_drp_backoff_win bow;
+ struct uwb_drp_avail drp_avail;
+ struct list_head reservations;
+ struct list_head cnflt_alien_list;
+ struct uwb_mas_bm cnflt_alien_bitmap;
+ struct mutex rsvs_mutex;
+ spinlock_t rsvs_lock;
+ struct workqueue_struct *rsv_workq;
+
+ struct delayed_work rsv_update_work;
+ struct delayed_work rsv_alien_bp_work;
+ int set_drp_ie_pending;
+ struct mutex ies_mutex;
+ struct uwb_rc_cmd_set_ie *ies;
+ size_t ies_capacity;
+
+ struct list_head pals;
+ int active_pals;
+
+ struct uwb_dbg *dbg;
+};
+
+
+/**
+ * struct uwb_pal - a UWB PAL
+ * @name: descriptive name for this PAL (wusbhc, wlp, etc.).
+ * @device: a device for the PAL. Used to link the PAL and the radio
+ * controller in sysfs.
+ * @rc: the radio controller the PAL uses.
+ * @channel_changed: called when the channel used by the radio changes.
+ * A channel of -1 means the channel has been stopped.
+ * @new_rsv: called when a peer requests a reservation (may be NULL if
+ * the PAL cannot accept reservation requests).
+ * @channel: channel being used by the PAL; 0 if the PAL isn't using
+ * the radio; -1 if the PAL wishes to use the radio but
+ * cannot.
+ * @debugfs_dir: a debugfs directory which the PAL can use for its own
+ * debugfs files.
+ *
+ * A Protocol Adaptation Layer (PAL) is a user of the WiMedia UWB
+ * radio platform (e.g., WUSB, WLP or Bluetooth UWB AMP).
+ *
+ * The PALs using a radio controller must register themselves to
+ * permit the UWB stack to coordinate usage of the radio between the
+ * various PALs or to allow PALs to response to certain requests from
+ * peers.
+ *
+ * A struct uwb_pal should be embedded in a containing structure
+ * belonging to the PAL and initialized with uwb_pal_init()). Fields
+ * should be set appropriately by the PAL before registering the PAL
+ * with uwb_pal_register().
+ */
+struct uwb_pal {
+ struct list_head node;
+ const char *name;
+ struct device *device;
+ struct uwb_rc *rc;
+
+ void (*channel_changed)(struct uwb_pal *pal, int channel);
+ void (*new_rsv)(struct uwb_pal *pal, struct uwb_rsv *rsv);
+
+ int channel;
+ struct dentry *debugfs_dir;
+};
+
+void uwb_pal_init(struct uwb_pal *pal);
+int uwb_pal_register(struct uwb_pal *pal);
+void uwb_pal_unregister(struct uwb_pal *pal);
+
+int uwb_radio_start(struct uwb_pal *pal);
+void uwb_radio_stop(struct uwb_pal *pal);
+
+/*
+ * General public API
+ *
+ * This API can be used by UWB device drivers or by those implementing
+ * UWB Radio Controllers
+ */
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+ const struct uwb_dev_addr *devaddr);
+struct uwb_dev *uwb_dev_get_by_rc(struct uwb_dev *, struct uwb_rc *);
+static inline void uwb_dev_get(struct uwb_dev *uwb_dev)
+{
+ get_device(&uwb_dev->dev);
+}
+static inline void uwb_dev_put(struct uwb_dev *uwb_dev)
+{
+ put_device(&uwb_dev->dev);
+}
+struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev);
+
+/**
+ * Callback function for 'uwb_{dev,rc}_foreach()'.
+ *
+ * @dev: Linux device instance
+ * 'uwb_dev = container_of(dev, struct uwb_dev, dev)'
+ * @priv: Data passed by the caller to 'uwb_{dev,rc}_foreach()'.
+ *
+ * @returns: 0 to continue the iterations, any other val to stop
+ * iterating and return the value to the caller of
+ * _foreach().
+ */
+typedef int (*uwb_dev_for_each_f)(struct device *dev, void *priv);
+int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f func, void *priv);
+
+struct uwb_rc *uwb_rc_alloc(void);
+struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *);
+struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *);
+void uwb_rc_put(struct uwb_rc *rc);
+
+typedef void (*uwb_rc_cmd_cb_f)(struct uwb_rc *rc, void *arg,
+ struct uwb_rceb *reply, ssize_t reply_size);
+
+int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ u8 expected_type, u16 expected_event,
+ uwb_rc_cmd_cb_f cb, void *arg);
+ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ struct uwb_rceb *reply, size_t reply_size);
+ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ u8 expected_type, u16 expected_event,
+ struct uwb_rceb **preply);
+
+size_t __uwb_addr_print(char *, size_t, const unsigned char *, int);
+
+int uwb_rc_dev_addr_set(struct uwb_rc *, const struct uwb_dev_addr *);
+int uwb_rc_dev_addr_get(struct uwb_rc *, struct uwb_dev_addr *);
+int uwb_rc_mac_addr_set(struct uwb_rc *, const struct uwb_mac_addr *);
+int uwb_rc_mac_addr_get(struct uwb_rc *, struct uwb_mac_addr *);
+int __uwb_mac_addr_assigned_check(struct device *, void *);
+int __uwb_dev_addr_assigned_check(struct device *, void *);
+
+/* Print in @buf a pretty repr of @addr */
+static inline size_t uwb_dev_addr_print(char *buf, size_t buf_size,
+ const struct uwb_dev_addr *addr)
+{
+ return __uwb_addr_print(buf, buf_size, addr->data, 0);
+}
+
+/* Print in @buf a pretty repr of @addr */
+static inline size_t uwb_mac_addr_print(char *buf, size_t buf_size,
+ const struct uwb_mac_addr *addr)
+{
+ return __uwb_addr_print(buf, buf_size, addr->data, 1);
+}
+
+/* @returns 0 if device addresses @addr2 and @addr1 are equal */
+static inline int uwb_dev_addr_cmp(const struct uwb_dev_addr *addr1,
+ const struct uwb_dev_addr *addr2)
+{
+ return memcmp(addr1, addr2, sizeof(*addr1));
+}
+
+/* @returns 0 if MAC addresses @addr2 and @addr1 are equal */
+static inline int uwb_mac_addr_cmp(const struct uwb_mac_addr *addr1,
+ const struct uwb_mac_addr *addr2)
+{
+ return memcmp(addr1, addr2, sizeof(*addr1));
+}
+
+/* @returns !0 if a MAC @addr is a broadcast address */
+static inline int uwb_mac_addr_bcast(const struct uwb_mac_addr *addr)
+{
+ struct uwb_mac_addr bcast = {
+ .data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+ };
+ return !uwb_mac_addr_cmp(addr, &bcast);
+}
+
+/* @returns !0 if a MAC @addr is all zeroes*/
+static inline int uwb_mac_addr_unset(const struct uwb_mac_addr *addr)
+{
+ struct uwb_mac_addr unset = {
+ .data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+ };
+ return !uwb_mac_addr_cmp(addr, &unset);
+}
+
+/* @returns !0 if the address is in use. */
+static inline unsigned __uwb_dev_addr_assigned(struct uwb_rc *rc,
+ struct uwb_dev_addr *addr)
+{
+ return uwb_dev_for_each(rc, __uwb_dev_addr_assigned_check, addr);
+}
+
+/*
+ * UWB Radio Controller API
+ *
+ * This API is used (in addition to the general API) to implement UWB
+ * Radio Controllers.
+ */
+void uwb_rc_init(struct uwb_rc *);
+int uwb_rc_add(struct uwb_rc *, struct device *dev, void *rc_priv);
+void uwb_rc_rm(struct uwb_rc *);
+void uwb_rc_neh_grok(struct uwb_rc *, void *, size_t);
+void uwb_rc_neh_error(struct uwb_rc *, int);
+void uwb_rc_reset_all(struct uwb_rc *rc);
+void uwb_rc_pre_reset(struct uwb_rc *rc);
+int uwb_rc_post_reset(struct uwb_rc *rc);
+
+/**
+ * uwb_rsv_is_owner - is the owner of this reservation the RC?
+ * @rsv: the reservation
+ */
+static inline bool uwb_rsv_is_owner(struct uwb_rsv *rsv)
+{
+ return rsv->owner == &rsv->rc->uwb_dev;
+}
+
+/**
+ * enum uwb_notifs - UWB events that can be passed to any listeners
+ * @UWB_NOTIF_ONAIR: a new neighbour has joined the beacon group.
+ * @UWB_NOTIF_OFFAIR: a neighbour has left the beacon group.
+ *
+ * Higher layers can register callback functions with the radio
+ * controller using uwb_notifs_register(). The radio controller
+ * maintains a list of all registered handlers and will notify all
+ * nodes when an event occurs.
+ */
+enum uwb_notifs {
+ UWB_NOTIF_ONAIR,
+ UWB_NOTIF_OFFAIR,
+};
+
+/* Callback function registered with UWB */
+struct uwb_notifs_handler {
+ struct list_head list_node;
+ void (*cb)(void *, struct uwb_dev *, enum uwb_notifs);
+ void *data;
+};
+
+int uwb_notifs_register(struct uwb_rc *, struct uwb_notifs_handler *);
+int uwb_notifs_deregister(struct uwb_rc *, struct uwb_notifs_handler *);
+
+
+/**
+ * UWB radio controller Event Size Entry (for creating entry tables)
+ *
+ * WUSB and WHCI define events and notifications, and they might have
+ * fixed or variable size.
+ *
+ * Each event/notification has a size which is not necessarily known
+ * in advance based on the event code. As well, vendor specific
+ * events/notifications will have a size impossible to determine
+ * unless we know about the device's specific details.
+ *
+ * It was way too smart of the spec writers not to think that it would
+ * be impossible for a generic driver to skip over vendor specific
+ * events/notifications if there are no LENGTH fields in the HEADER of
+ * each message...the transaction size cannot be counted on as the
+ * spec does not forbid to pack more than one event in a single
+ * transaction.
+ *
+ * Thus, we guess sizes with tables (or for events, when you know the
+ * size ahead of time you can use uwb_rc_neh_extra_size*()). We
+ * register tables with the known events and their sizes, and then we
+ * traverse those tables. For those with variable length, we provide a
+ * way to lookup the size inside the event/notification's
+ * payload. This allows device-specific event size tables to be
+ * registered.
+ *
+ * @size: Size of the payload
+ *
+ * @offset: if != 0, at offset @offset-1 starts a field with a length
+ * that has to be added to @size. The format of the field is
+ * given by @type.
+ *
+ * @type: Type and length of the offset field. Most common is LE 16
+ * bits (that's why that is zero); others are there mostly to
+ * cover for bugs and weirdos.
+ */
+struct uwb_est_entry {
+ size_t size;
+ unsigned offset;
+ enum { UWB_EST_16 = 0, UWB_EST_8 = 1 } type;
+};
+
+int uwb_est_register(u8 type, u8 code_high, u16 vendor, u16 product,
+ const struct uwb_est_entry *, size_t entries);
+int uwb_est_unregister(u8 type, u8 code_high, u16 vendor, u16 product,
+ const struct uwb_est_entry *, size_t entries);
+ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
+ size_t len);
+
+/* -- Misc */
+
+enum {
+ EDC_MAX_ERRORS = 10,
+ EDC_ERROR_TIMEFRAME = HZ,
+};
+
+/* error density counter */
+struct edc {
+ unsigned long timestart;
+ u16 errorcount;
+};
+
+static inline
+void edc_init(struct edc *edc)
+{
+ edc->timestart = jiffies;
+}
+
+/* Called when an error occurred.
+ * This is way to determine if the number of acceptable errors per time
+ * period has been exceeded. It is not accurate as there are cases in which
+ * this scheme will not work, for example if there are periodic occurrences
+ * of errors that straddle updates to the start time. This scheme is
+ * sufficient for our usage.
+ *
+ * @returns 1 if maximum acceptable errors per timeframe has been exceeded.
+ */
+static inline int edc_inc(struct edc *err_hist, u16 max_err, u16 timeframe)
+{
+ unsigned long now;
+
+ now = jiffies;
+ if (now - err_hist->timestart > timeframe) {
+ err_hist->errorcount = 1;
+ err_hist->timestart = now;
+ } else if (++err_hist->errorcount > max_err) {
+ err_hist->errorcount = 0;
+ err_hist->timestart = now;
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Information Element handling */
+
+struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len);
+int uwb_rc_ie_add(struct uwb_rc *uwb_rc, const struct uwb_ie_hdr *ies, size_t size);
+int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id);
+
+/*
+ * Transmission statistics
+ *
+ * UWB uses LQI and RSSI (one byte values) for reporting radio signal
+ * strength and line quality indication. We do quick and dirty
+ * averages of those. They are signed values, btw.
+ *
+ * For 8 bit quantities, we keep the min, the max, an accumulator
+ * (@sigma) and a # of samples. When @samples gets to 255, we compute
+ * the average (@sigma / @samples), place it in @sigma and reset
+ * @samples to 1 (so we use it as the first sample).
+ *
+ * Now, statistically speaking, probably I am kicking the kidneys of
+ * some books I have in my shelves collecting dust, but I just want to
+ * get an approx, not the Nobel.
+ *
+ * LOCKING: there is no locking per se, but we try to keep a lockless
+ * schema. Only _add_samples() modifies the values--as long as you
+ * have other locking on top that makes sure that no two calls of
+ * _add_sample() happen at the same time, then we are fine. Now, for
+ * resetting the values we just set @samples to 0 and that makes the
+ * next _add_sample() to start with defaults. Reading the values in
+ * _show() currently can race, so you need to make sure the calls are
+ * under the same lock that protects calls to _add_sample(). FIXME:
+ * currently unlocked (It is not ultraprecise but does the trick. Bite
+ * me).
+ */
+struct stats {
+ s8 min, max;
+ s16 sigma;
+ atomic_t samples;
+};
+
+static inline
+void stats_init(struct stats *stats)
+{
+ atomic_set(&stats->samples, 0);
+ wmb();
+}
+
+static inline
+void stats_add_sample(struct stats *stats, s8 sample)
+{
+ s8 min, max;
+ s16 sigma;
+ unsigned samples = atomic_read(&stats->samples);
+ if (samples == 0) { /* it was zero before, so we initialize */
+ min = 127;
+ max = -128;
+ sigma = 0;
+ } else {
+ min = stats->min;
+ max = stats->max;
+ sigma = stats->sigma;
+ }
+
+ if (sample < min) /* compute new values */
+ min = sample;
+ else if (sample > max)
+ max = sample;
+ sigma += sample;
+
+ stats->min = min; /* commit */
+ stats->max = max;
+ stats->sigma = sigma;
+ if (atomic_add_return(1, &stats->samples) > 255) {
+ /* wrapped around! reset */
+ stats->sigma = sigma / 256;
+ atomic_set(&stats->samples, 1);
+ }
+}
+
+static inline ssize_t stats_show(struct stats *stats, char *buf)
+{
+ int min, max, avg;
+ int samples = atomic_read(&stats->samples);
+ if (samples == 0)
+ min = max = avg = 0;
+ else {
+ min = stats->min;
+ max = stats->max;
+ avg = stats->sigma / samples;
+ }
+ return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", min, max, avg);
+}
+
+static inline ssize_t stats_store(struct stats *stats, const char *buf,
+ size_t size)
+{
+ stats_init(stats);
+ return size;
+}
+
+#endif /* #ifndef __LINUX__UWB_H__ */
diff --git a/drivers/staging/uwb/uwbd.c b/drivers/staging/uwb/uwbd.c
new file mode 100644
index 000000000000..dc5c743d4f5f
--- /dev/null
+++ b/drivers/staging/uwb/uwbd.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Neighborhood Management Daemon
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This daemon takes care of maintaing information that describes the
+ * UWB neighborhood that the radios in this machine can see. It also
+ * keeps a tab of which devices are visible, makes sure each HC sits
+ * on a different channel to avoid interfering, etc.
+ *
+ * Different drivers (radio controller, device, any API in general)
+ * communicate with this daemon through an event queue. Daemon wakes
+ * up, takes a list of events and handles them one by one; handling
+ * function is extracted from a table based on the event's type and
+ * subtype. Events are freed only if the handling function says so.
+ *
+ * . Lock protecting the event list has to be an spinlock and locked
+ * with IRQSAVE because it might be called from an interrupt
+ * context (ie: when events arrive and the notification drops
+ * down from the ISR).
+ *
+ * . UWB radio controller drivers queue events to the daemon using
+ * uwbd_event_queue(). They just get the event, chew it to make it
+ * look like UWBD likes it and pass it in a buffer allocated with
+ * uwb_event_alloc().
+ *
+ * EVENTS
+ *
+ * Events have a type, a subtype, a length, some other stuff and the
+ * data blob, which depends on the event. The header is 'struct
+ * uwb_event'; for payloads, see 'struct uwbd_evt_*'.
+ *
+ * EVENT HANDLER TABLES
+ *
+ * To find a handling function for an event, the type is used to index
+ * a subtype-table in the type-table. The subtype-table is indexed
+ * with the subtype to get the function that handles the event. Start
+ * with the main type-table 'uwbd_evt_type_handler'.
+ *
+ * DEVICES
+ *
+ * Devices are created when a bunch of beacons have been received and
+ * it is stablished that the device has stable radio presence. CREATED
+ * only, not configured. Devices are ONLY configured when an
+ * Application-Specific IE Probe is receieved, in which the device
+ * declares which Protocol ID it groks. Then the device is CONFIGURED
+ * (and the driver->probe() stuff of the device model is invoked).
+ *
+ * Devices are considered disconnected when a certain number of
+ * beacons are not received in an amount of time.
+ *
+ * Handler functions are called normally uwbd_evt_handle_*().
+ */
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/freezer.h>
+
+#include "uwb-internal.h"
+
+/*
+ * UWBD Event handler function signature
+ *
+ * Return !0 if the event needs not to be freed (ie the handler
+ * takes/took care of it). 0 means the daemon code will free the
+ * event.
+ *
+ * @evt->rc is already referenced and guaranteed to exist. See
+ * uwb_evt_handle().
+ */
+typedef int (*uwbd_evt_handler_f)(struct uwb_event *);
+
+/**
+ * Properties of a UWBD event
+ *
+ * @handler: the function that will handle this event
+ * @name: text name of event
+ */
+struct uwbd_event {
+ uwbd_evt_handler_f handler;
+ const char *name;
+};
+
+/* Table of handlers for and properties of the UWBD Radio Control Events */
+static struct uwbd_event uwbd_urc_events[] = {
+ [UWB_RC_EVT_IE_RCV] = {
+ .handler = uwbd_evt_handle_rc_ie_rcv,
+ .name = "IE_RECEIVED"
+ },
+ [UWB_RC_EVT_BEACON] = {
+ .handler = uwbd_evt_handle_rc_beacon,
+ .name = "BEACON_RECEIVED"
+ },
+ [UWB_RC_EVT_BEACON_SIZE] = {
+ .handler = uwbd_evt_handle_rc_beacon_size,
+ .name = "BEACON_SIZE_CHANGE"
+ },
+ [UWB_RC_EVT_BPOIE_CHANGE] = {
+ .handler = uwbd_evt_handle_rc_bpoie_change,
+ .name = "BPOIE_CHANGE"
+ },
+ [UWB_RC_EVT_BP_SLOT_CHANGE] = {
+ .handler = uwbd_evt_handle_rc_bp_slot_change,
+ .name = "BP_SLOT_CHANGE"
+ },
+ [UWB_RC_EVT_DRP_AVAIL] = {
+ .handler = uwbd_evt_handle_rc_drp_avail,
+ .name = "DRP_AVAILABILITY_CHANGE"
+ },
+ [UWB_RC_EVT_DRP] = {
+ .handler = uwbd_evt_handle_rc_drp,
+ .name = "DRP"
+ },
+ [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
+ .handler = uwbd_evt_handle_rc_dev_addr_conflict,
+ .name = "DEV_ADDR_CONFLICT",
+ },
+};
+
+
+
+struct uwbd_evt_type_handler {
+ const char *name;
+ struct uwbd_event *uwbd_events;
+ size_t size;
+};
+
+/* Table of handlers for each UWBD Event type. */
+static struct uwbd_evt_type_handler uwbd_urc_evt_type_handlers[] = {
+ [UWB_RC_CET_GENERAL] = {
+ .name = "URC",
+ .uwbd_events = uwbd_urc_events,
+ .size = ARRAY_SIZE(uwbd_urc_events),
+ },
+};
+
+static const struct uwbd_event uwbd_message_handlers[] = {
+ [UWB_EVT_MSG_RESET] = {
+ .handler = uwbd_msg_handle_reset,
+ .name = "reset",
+ },
+};
+
+/*
+ * Handle an URC event passed to the UWB Daemon
+ *
+ * @evt: the event to handle
+ * @returns: 0 if the event can be kfreed, !0 on the contrary
+ * (somebody else took ownership) [coincidentally, returning
+ * a <0 errno code will free it :)].
+ *
+ * Looks up the two indirection tables (one for the type, one for the
+ * subtype) to decide which function handles it and then calls the
+ * handler.
+ *
+ * The event structure passed to the event handler has the radio
+ * controller in @evt->rc referenced. The reference will be dropped
+ * once the handler returns, so if it needs it for longer (async),
+ * it'll need to take another one.
+ */
+static
+int uwbd_event_handle_urc(struct uwb_event *evt)
+{
+ int result = -EINVAL;
+ struct uwbd_evt_type_handler *type_table;
+ uwbd_evt_handler_f handler;
+ u8 type, context;
+ u16 event;
+
+ type = evt->notif.rceb->bEventType;
+ event = le16_to_cpu(evt->notif.rceb->wEvent);
+ context = evt->notif.rceb->bEventContext;
+
+ if (type >= ARRAY_SIZE(uwbd_urc_evt_type_handlers))
+ goto out;
+ type_table = &uwbd_urc_evt_type_handlers[type];
+ if (type_table->uwbd_events == NULL)
+ goto out;
+ if (event >= type_table->size)
+ goto out;
+ handler = type_table->uwbd_events[event].handler;
+ if (handler == NULL)
+ goto out;
+
+ result = (*handler)(evt);
+out:
+ if (result < 0)
+ dev_err(&evt->rc->uwb_dev.dev,
+ "UWBD: event 0x%02x/%04x/%02x, handling failed: %d\n",
+ type, event, context, result);
+ return result;
+}
+
+static void uwbd_event_handle_message(struct uwb_event *evt)
+{
+ struct uwb_rc *rc;
+ int result;
+
+ rc = evt->rc;
+
+ if (evt->message < 0 || evt->message >= ARRAY_SIZE(uwbd_message_handlers)) {
+ dev_err(&rc->uwb_dev.dev, "UWBD: invalid message type %d\n", evt->message);
+ return;
+ }
+
+ result = uwbd_message_handlers[evt->message].handler(evt);
+ if (result < 0)
+ dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n",
+ uwbd_message_handlers[evt->message].name, result);
+}
+
+static void uwbd_event_handle(struct uwb_event *evt)
+{
+ struct uwb_rc *rc;
+ int should_keep;
+
+ rc = evt->rc;
+
+ if (rc->ready) {
+ switch (evt->type) {
+ case UWB_EVT_TYPE_NOTIF:
+ should_keep = uwbd_event_handle_urc(evt);
+ if (should_keep <= 0)
+ kfree(evt->notif.rceb);
+ break;
+ case UWB_EVT_TYPE_MSG:
+ uwbd_event_handle_message(evt);
+ break;
+ default:
+ dev_err(&rc->uwb_dev.dev, "UWBD: invalid event type %d\n", evt->type);
+ break;
+ }
+ }
+
+ __uwb_rc_put(rc); /* for the __uwb_rc_get() in uwb_rc_notif_cb() */
+}
+
+/**
+ * UWB Daemon
+ *
+ * Listens to all UWB notifications and takes care to track the state
+ * of the UWB neighbourhood for the kernel. When we do a run, we
+ * spinlock, move the list to a private copy and release the
+ * lock. Hold it as little as possible. Not a conflict: it is
+ * guaranteed we own the events in the private list.
+ *
+ * FIXME: should change so we don't have a 1HZ timer all the time, but
+ * only if there are devices.
+ */
+static int uwbd(void *param)
+{
+ struct uwb_rc *rc = param;
+ unsigned long flags;
+ struct uwb_event *evt;
+ int should_stop = 0;
+
+ while (1) {
+ wait_event_interruptible_timeout(
+ rc->uwbd.wq,
+ !list_empty(&rc->uwbd.event_list)
+ || (should_stop = kthread_should_stop()),
+ HZ);
+ if (should_stop)
+ break;
+
+ spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
+ if (!list_empty(&rc->uwbd.event_list)) {
+ evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node);
+ list_del(&evt->list_node);
+ } else
+ evt = NULL;
+ spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
+
+ if (evt) {
+ uwbd_event_handle(evt);
+ kfree(evt);
+ }
+
+ uwb_beca_purge(rc); /* Purge devices that left */
+ }
+ return 0;
+}
+
+
+/** Start the UWB daemon */
+void uwbd_start(struct uwb_rc *rc)
+{
+ struct task_struct *task = kthread_run(uwbd, rc, "uwbd");
+ if (IS_ERR(task)) {
+ rc->uwbd.task = NULL;
+ printk(KERN_ERR "UWB: Cannot start management daemon; "
+ "UWB won't work\n");
+ } else {
+ rc->uwbd.task = task;
+ rc->uwbd.pid = rc->uwbd.task->pid;
+ }
+}
+
+/* Stop the UWB daemon and free any unprocessed events */
+void uwbd_stop(struct uwb_rc *rc)
+{
+ if (rc->uwbd.task)
+ kthread_stop(rc->uwbd.task);
+ uwbd_flush(rc);
+}
+
+/*
+ * Queue an event for the management daemon
+ *
+ * When some lower layer receives an event, it uses this function to
+ * push it forward to the UWB daemon.
+ *
+ * Once you pass the event, you don't own it any more, but the daemon
+ * does. It will uwb_event_free() it when done, so make sure you
+ * uwb_event_alloc()ed it or bad things will happen.
+ *
+ * If the daemon is not running, we just free the event.
+ */
+void uwbd_event_queue(struct uwb_event *evt)
+{
+ struct uwb_rc *rc = evt->rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
+ if (rc->uwbd.pid != 0) {
+ list_add(&evt->list_node, &rc->uwbd.event_list);
+ wake_up_all(&rc->uwbd.wq);
+ } else {
+ __uwb_rc_put(evt->rc);
+ if (evt->type == UWB_EVT_TYPE_NOTIF)
+ kfree(evt->notif.rceb);
+ kfree(evt);
+ }
+ spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
+ return;
+}
+
+void uwbd_flush(struct uwb_rc *rc)
+{
+ struct uwb_event *evt, *nxt;
+
+ spin_lock_irq(&rc->uwbd.event_list_lock);
+ list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) {
+ if (evt->rc == rc) {
+ __uwb_rc_put(rc);
+ list_del(&evt->list_node);
+ if (evt->type == UWB_EVT_TYPE_NOTIF)
+ kfree(evt->notif.rceb);
+ kfree(evt);
+ }
+ }
+ spin_unlock_irq(&rc->uwbd.event_list_lock);
+}
diff --git a/drivers/staging/uwb/whc-rc.c b/drivers/staging/uwb/whc-rc.c
new file mode 100644
index 000000000000..34020ed351ab
--- /dev/null
+++ b/drivers/staging/uwb/whc-rc.c
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Wireless Host Controller: Radio Control Interface (WHCI v0.95[2.3])
+ * Radio Control command/event transport to the UWB stack
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Initialize and hook up the Radio Control interface.
+ *
+ * For each device probed, creates an 'struct whcrc' which contains
+ * just the representation of the UWB Radio Controller, and the logic
+ * for reading notifications and passing them to the UWB Core.
+ *
+ * So we initialize all of those, register the UWB Radio Controller
+ * and setup the notification/event handle to pipe the notifications
+ * to the UWB management Daemon.
+ *
+ * Once uwb_rc_add() is called, the UWB stack takes control, resets
+ * the radio and readies the device to take commands the UWB
+ * API/user-space.
+ *
+ * Note this driver is just a transport driver; the commands are
+ * formed at the UWB stack and given to this driver who will deliver
+ * them to the hw and transfer the replies/notifications back to the
+ * UWB stack through the UWB daemon (UWBD).
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "uwb.h"
+#include "include/whci.h"
+#include "include/umc.h"
+
+#include "uwb-internal.h"
+
+/**
+ * Descriptor for an instance of the UWB Radio Control Driver that
+ * attaches to the URC interface of the WHCI PCI card.
+ *
+ * Unless there is a lock specific to the 'data members', all access
+ * is protected by uwb_rc->mutex.
+ */
+struct whcrc {
+ struct umc_dev *umc_dev;
+ struct uwb_rc *uwb_rc; /* UWB host controller */
+
+ unsigned long area;
+ void __iomem *rc_base;
+ size_t rc_len;
+ spinlock_t irq_lock;
+
+ void *evt_buf, *cmd_buf;
+ dma_addr_t evt_dma_buf, cmd_dma_buf;
+ wait_queue_head_t cmd_wq;
+ struct work_struct event_work;
+};
+
+/**
+ * Execute an UWB RC command on WHCI/RC
+ *
+ * @rc: Instance of a Radio Controller that is a whcrc
+ * @cmd: Buffer containing the RCCB and payload to execute
+ * @cmd_size: Size of the command buffer.
+ *
+ * We copy the command into whcrc->cmd_buf (as it is pretty and
+ * aligned`and physically contiguous) and then press the right keys in
+ * the controller's URCCMD register to get it to read it. We might
+ * have to wait for the cmd_sem to be open to us.
+ *
+ * NOTE: rc's mutex has to be locked
+ */
+static int whcrc_cmd(struct uwb_rc *uwb_rc,
+ const struct uwb_rccb *cmd, size_t cmd_size)
+{
+ int result = 0;
+ struct whcrc *whcrc = uwb_rc->priv;
+ struct device *dev = &whcrc->umc_dev->dev;
+ u32 urccmd;
+
+ if (cmd_size >= 4096)
+ return -EINVAL;
+
+ /*
+ * If the URC is halted, then the hardware has reset itself.
+ * Attempt to recover by restarting the device and then return
+ * an error as it's likely that the current command isn't
+ * valid for a newly started RC.
+ */
+ if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) {
+ dev_err(dev, "requesting reset of halted radio controller\n");
+ uwb_rc_reset_all(uwb_rc);
+ return -EIO;
+ }
+
+ result = wait_event_timeout(whcrc->cmd_wq,
+ !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2);
+ if (result == 0) {
+ dev_err(dev, "device is not ready to execute commands\n");
+ return -ETIMEDOUT;
+ }
+
+ memmove(whcrc->cmd_buf, cmd, cmd_size);
+ le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR);
+
+ spin_lock(&whcrc->irq_lock);
+ urccmd = le_readl(whcrc->rc_base + URCCMD);
+ urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK);
+ le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size,
+ whcrc->rc_base + URCCMD);
+ spin_unlock(&whcrc->irq_lock);
+
+ return 0;
+}
+
+static int whcrc_reset(struct uwb_rc *rc)
+{
+ struct whcrc *whcrc = rc->priv;
+
+ return umc_controller_reset(whcrc->umc_dev);
+}
+
+/**
+ * Reset event reception mechanism and tell hw we are ready to get more
+ *
+ * We have read all the events in the event buffer, so we are ready to
+ * reset it to the beginning.
+ *
+ * This is only called during initialization or after an event buffer
+ * has been retired. This means we can be sure that event processing
+ * is disabled and it's safe to update the URCEVTADDR register.
+ *
+ * There's no need to wait for the event processing to start as the
+ * URC will not clear URCCMD_ACTIVE until (internal) event buffer
+ * space is available.
+ */
+static
+void whcrc_enable_events(struct whcrc *whcrc)
+{
+ u32 urccmd;
+
+ le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR);
+
+ spin_lock(&whcrc->irq_lock);
+ urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE;
+ le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD);
+ spin_unlock(&whcrc->irq_lock);
+}
+
+static void whcrc_event_work(struct work_struct *work)
+{
+ struct whcrc *whcrc = container_of(work, struct whcrc, event_work);
+ size_t size;
+ u64 urcevtaddr;
+
+ urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR);
+ size = urcevtaddr & URCEVTADDR_OFFSET_MASK;
+
+ uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size);
+ whcrc_enable_events(whcrc);
+}
+
+/**
+ * Catch interrupts?
+ *
+ * We ack inmediately (and expect the hw to do the right thing and
+ * raise another IRQ if things have changed :)
+ */
+static
+irqreturn_t whcrc_irq_cb(int irq, void *_whcrc)
+{
+ struct whcrc *whcrc = _whcrc;
+ struct device *dev = &whcrc->umc_dev->dev;
+ u32 urcsts;
+
+ urcsts = le_readl(whcrc->rc_base + URCSTS);
+ if (!(urcsts & URCSTS_INT_MASK))
+ return IRQ_NONE;
+ le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS);
+
+ if (urcsts & URCSTS_HSE) {
+ dev_err(dev, "host system error -- hardware halted\n");
+ /* FIXME: do something sensible here */
+ goto out;
+ }
+ if (urcsts & URCSTS_ER)
+ schedule_work(&whcrc->event_work);
+ if (urcsts & URCSTS_RCI)
+ wake_up_all(&whcrc->cmd_wq);
+out:
+ return IRQ_HANDLED;
+}
+
+
+/**
+ * Initialize a UMC RC interface: map regions, get (shared) IRQ
+ */
+static
+int whcrc_setup_rc_umc(struct whcrc *whcrc)
+{
+ int result = 0;
+ struct device *dev = &whcrc->umc_dev->dev;
+ struct umc_dev *umc_dev = whcrc->umc_dev;
+
+ whcrc->area = umc_dev->resource.start;
+ whcrc->rc_len = resource_size(&umc_dev->resource);
+ result = -EBUSY;
+ if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) == NULL) {
+ dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n",
+ whcrc->rc_len, whcrc->area, result);
+ goto error_request_region;
+ }
+
+ whcrc->rc_base = ioremap_nocache(whcrc->area, whcrc->rc_len);
+ if (whcrc->rc_base == NULL) {
+ dev_err(dev, "can't ioremap registers (%zu bytes @ 0x%lx): %d\n",
+ whcrc->rc_len, whcrc->area, result);
+ goto error_ioremap_nocache;
+ }
+
+ result = request_irq(umc_dev->irq, whcrc_irq_cb, IRQF_SHARED,
+ KBUILD_MODNAME, whcrc);
+ if (result < 0) {
+ dev_err(dev, "can't allocate IRQ %d: %d\n",
+ umc_dev->irq, result);
+ goto error_request_irq;
+ }
+
+ result = -ENOMEM;
+ whcrc->cmd_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
+ &whcrc->cmd_dma_buf, GFP_KERNEL);
+ if (whcrc->cmd_buf == NULL) {
+ dev_err(dev, "Can't allocate cmd transfer buffer\n");
+ goto error_cmd_buffer;
+ }
+
+ whcrc->evt_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
+ &whcrc->evt_dma_buf, GFP_KERNEL);
+ if (whcrc->evt_buf == NULL) {
+ dev_err(dev, "Can't allocate evt transfer buffer\n");
+ goto error_evt_buffer;
+ }
+ return 0;
+
+error_evt_buffer:
+ dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
+ whcrc->cmd_dma_buf);
+error_cmd_buffer:
+ free_irq(umc_dev->irq, whcrc);
+error_request_irq:
+ iounmap(whcrc->rc_base);
+error_ioremap_nocache:
+ release_mem_region(whcrc->area, whcrc->rc_len);
+error_request_region:
+ return result;
+}
+
+
+/**
+ * Release RC's UMC resources
+ */
+static
+void whcrc_release_rc_umc(struct whcrc *whcrc)
+{
+ struct umc_dev *umc_dev = whcrc->umc_dev;
+
+ dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->evt_buf,
+ whcrc->evt_dma_buf);
+ dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
+ whcrc->cmd_dma_buf);
+ free_irq(umc_dev->irq, whcrc);
+ iounmap(whcrc->rc_base);
+ release_mem_region(whcrc->area, whcrc->rc_len);
+}
+
+
+/**
+ * whcrc_start_rc - start a WHCI radio controller
+ * @whcrc: the radio controller to start
+ *
+ * Reset the UMC device, start the radio controller, enable events and
+ * finally enable interrupts.
+ */
+static int whcrc_start_rc(struct uwb_rc *rc)
+{
+ struct whcrc *whcrc = rc->priv;
+ struct device *dev = &whcrc->umc_dev->dev;
+
+ /* Reset the thing */
+ le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD);
+ if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0,
+ 5000, "hardware reset") < 0)
+ return -EBUSY;
+
+ /* Set the event buffer, start the controller (enable IRQs later) */
+ le_writel(0, whcrc->rc_base + URCINTR);
+ le_writel(URCCMD_RS, whcrc->rc_base + URCCMD);
+ if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0,
+ 5000, "radio controller start") < 0)
+ return -ETIMEDOUT;
+ whcrc_enable_events(whcrc);
+ le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR);
+ return 0;
+}
+
+
+/**
+ * whcrc_stop_rc - stop a WHCI radio controller
+ * @whcrc: the radio controller to stop
+ *
+ * Disable interrupts and cancel any pending event processing work
+ * before clearing the Run/Stop bit.
+ */
+static
+void whcrc_stop_rc(struct uwb_rc *rc)
+{
+ struct whcrc *whcrc = rc->priv;
+ struct umc_dev *umc_dev = whcrc->umc_dev;
+
+ le_writel(0, whcrc->rc_base + URCINTR);
+ cancel_work_sync(&whcrc->event_work);
+
+ le_writel(0, whcrc->rc_base + URCCMD);
+ whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS,
+ URCSTS_HALTED, URCSTS_HALTED, 100, "radio controller stop");
+}
+
+static void whcrc_init(struct whcrc *whcrc)
+{
+ spin_lock_init(&whcrc->irq_lock);
+ init_waitqueue_head(&whcrc->cmd_wq);
+ INIT_WORK(&whcrc->event_work, whcrc_event_work);
+}
+
+/**
+ * Initialize the radio controller.
+ *
+ * NOTE: we setup whcrc->uwb_rc before calling uwb_rc_add(); in the
+ * IRQ handler we use that to determine if the hw is ready to
+ * handle events. Looks like a race condition, but it really is
+ * not.
+ */
+static
+int whcrc_probe(struct umc_dev *umc_dev)
+{
+ int result;
+ struct uwb_rc *uwb_rc;
+ struct whcrc *whcrc;
+ struct device *dev = &umc_dev->dev;
+
+ result = -ENOMEM;
+ uwb_rc = uwb_rc_alloc();
+ if (uwb_rc == NULL) {
+ dev_err(dev, "unable to allocate RC instance\n");
+ goto error_rc_alloc;
+ }
+ whcrc = kzalloc(sizeof(*whcrc), GFP_KERNEL);
+ if (whcrc == NULL) {
+ dev_err(dev, "unable to allocate WHC-RC instance\n");
+ goto error_alloc;
+ }
+ whcrc_init(whcrc);
+ whcrc->umc_dev = umc_dev;
+
+ result = whcrc_setup_rc_umc(whcrc);
+ if (result < 0) {
+ dev_err(dev, "Can't setup RC UMC interface: %d\n", result);
+ goto error_setup_rc_umc;
+ }
+ whcrc->uwb_rc = uwb_rc;
+
+ uwb_rc->owner = THIS_MODULE;
+ uwb_rc->cmd = whcrc_cmd;
+ uwb_rc->reset = whcrc_reset;
+ uwb_rc->start = whcrc_start_rc;
+ uwb_rc->stop = whcrc_stop_rc;
+
+ result = uwb_rc_add(uwb_rc, dev, whcrc);
+ if (result < 0)
+ goto error_rc_add;
+ umc_set_drvdata(umc_dev, whcrc);
+ return 0;
+
+error_rc_add:
+ whcrc_release_rc_umc(whcrc);
+error_setup_rc_umc:
+ kfree(whcrc);
+error_alloc:
+ uwb_rc_put(uwb_rc);
+error_rc_alloc:
+ return result;
+}
+
+/**
+ * Clean up the radio control resources
+ *
+ * When we up the command semaphore, everybody possibly held trying to
+ * execute a command should be granted entry and then they'll see the
+ * host is quiescing and up it (so it will chain to the next waiter).
+ * This should not happen (in any case), as we can only remove when
+ * there are no handles open...
+ */
+static void whcrc_remove(struct umc_dev *umc_dev)
+{
+ struct whcrc *whcrc = umc_get_drvdata(umc_dev);
+ struct uwb_rc *uwb_rc = whcrc->uwb_rc;
+
+ umc_set_drvdata(umc_dev, NULL);
+ uwb_rc_rm(uwb_rc);
+ whcrc_release_rc_umc(whcrc);
+ kfree(whcrc);
+ uwb_rc_put(uwb_rc);
+}
+
+static int whcrc_pre_reset(struct umc_dev *umc)
+{
+ struct whcrc *whcrc = umc_get_drvdata(umc);
+ struct uwb_rc *uwb_rc = whcrc->uwb_rc;
+
+ uwb_rc_pre_reset(uwb_rc);
+ return 0;
+}
+
+static int whcrc_post_reset(struct umc_dev *umc)
+{
+ struct whcrc *whcrc = umc_get_drvdata(umc);
+ struct uwb_rc *uwb_rc = whcrc->uwb_rc;
+
+ return uwb_rc_post_reset(uwb_rc);
+}
+
+/* PCI device ID's that we handle [so it gets loaded] */
+static struct pci_device_id __used whcrc_id_table[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+ { /* empty last entry */ }
+};
+MODULE_DEVICE_TABLE(pci, whcrc_id_table);
+
+static struct umc_driver whcrc_driver = {
+ .name = "whc-rc",
+ .cap_id = UMC_CAP_ID_WHCI_RC,
+ .probe = whcrc_probe,
+ .remove = whcrc_remove,
+ .pre_reset = whcrc_pre_reset,
+ .post_reset = whcrc_post_reset,
+};
+
+static int __init whcrc_driver_init(void)
+{
+ return umc_driver_register(&whcrc_driver);
+}
+module_init(whcrc_driver_init);
+
+static void __exit whcrc_driver_exit(void)
+{
+ umc_driver_unregister(&whcrc_driver);
+}
+module_exit(whcrc_driver_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless Host Controller Radio Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/whci.c b/drivers/staging/uwb/whci.c
new file mode 100644
index 000000000000..a8832f64d708
--- /dev/null
+++ b/drivers/staging/uwb/whci.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * WHCI UWB Multi-interface Controller enumerator.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include "include/whci.h"
+#include "include/umc.h"
+
+struct whci_card {
+ struct pci_dev *pci;
+ void __iomem *uwbbase;
+ u8 n_caps;
+ struct umc_dev *devs[0];
+};
+
+
+/* Fix faulty HW :( */
+static
+u64 whci_capdata_quirks(struct whci_card *card, u64 capdata)
+{
+ u64 capdata_orig = capdata;
+ struct pci_dev *pci_dev = card->pci;
+ if (pci_dev->vendor == PCI_VENDOR_ID_INTEL
+ && (pci_dev->device == 0x0c3b || pci_dev->device == 0004)
+ && pci_dev->class == 0x0d1010) {
+ switch (UWBCAPDATA_TO_CAP_ID(capdata)) {
+ /* WLP capability has 0x100 bytes of aperture */
+ case 0x80:
+ capdata |= 0x40 << 8; break;
+ /* WUSB capability has 0x80 bytes of aperture
+ * and ID is 1 */
+ case 0x02:
+ capdata &= ~0xffff;
+ capdata |= 0x2001;
+ break;
+ }
+ }
+ if (capdata_orig != capdata)
+ dev_warn(&pci_dev->dev,
+ "PCI v%04x d%04x c%06x#%02x: "
+ "corrected capdata from %016Lx to %016Lx\n",
+ pci_dev->vendor, pci_dev->device, pci_dev->class,
+ (unsigned)UWBCAPDATA_TO_CAP_ID(capdata),
+ (unsigned long long)capdata_orig,
+ (unsigned long long)capdata);
+ return capdata;
+}
+
+
+/**
+ * whci_wait_for - wait for a WHCI register to be set
+ *
+ * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'.
+ */
+int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result,
+ unsigned long max_ms, const char *tag)
+{
+ unsigned t = 0;
+ u32 val;
+ for (;;) {
+ val = le_readl(reg);
+ if ((val & mask) == result)
+ break;
+ if (t >= max_ms) {
+ dev_err(dev, "%s timed out\n", tag);
+ return -ETIMEDOUT;
+ }
+ msleep(10);
+ t += 10;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(whci_wait_for);
+
+
+/*
+ * NOTE: the capinfo and capdata registers are slightly different
+ * (size and cap-id fields). So for cap #0, we need to fill
+ * in. Size comes from the size of the register block
+ * (statically calculated); cap_id comes from nowhere, we use
+ * zero, that is reserved, for the radio controller, because
+ * none was defined at the spec level.
+ */
+static int whci_add_cap(struct whci_card *card, int n)
+{
+ struct umc_dev *umc;
+ u64 capdata;
+ int bar, err;
+
+ umc = umc_device_create(&card->pci->dev, n);
+ if (umc == NULL)
+ return -ENOMEM;
+
+ capdata = le_readq(card->uwbbase + UWBCAPDATA(n));
+
+ bar = UWBCAPDATA_TO_BAR(capdata) << 1;
+
+ capdata = whci_capdata_quirks(card, capdata);
+ /* Capability 0 is the radio controller. It's size is 32
+ * bytes (WHCI0.95[2.3, T2-9]). */
+ umc->version = UWBCAPDATA_TO_VERSION(capdata);
+ umc->cap_id = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata);
+ umc->bar = bar;
+ umc->resource.start = pci_resource_start(card->pci, bar)
+ + UWBCAPDATA_TO_OFFSET(capdata);
+ umc->resource.end = umc->resource.start
+ + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1;
+ umc->resource.name = dev_name(&umc->dev);
+ umc->resource.flags = card->pci->resource[bar].flags;
+ umc->resource.parent = &card->pci->resource[bar];
+ umc->irq = card->pci->irq;
+
+ err = umc_device_register(umc);
+ if (err < 0)
+ goto error;
+ card->devs[n] = umc;
+ return 0;
+
+error:
+ kfree(umc);
+ return err;
+}
+
+static void whci_del_cap(struct whci_card *card, int n)
+{
+ struct umc_dev *umc = card->devs[n];
+
+ umc_device_unregister(umc);
+}
+
+static int whci_n_caps(struct pci_dev *pci)
+{
+ void __iomem *uwbbase;
+ u64 capinfo;
+
+ uwbbase = pci_iomap(pci, 0, 8);
+ if (!uwbbase)
+ return -ENOMEM;
+ capinfo = le_readq(uwbbase + UWBCAPINFO);
+ pci_iounmap(pci, uwbbase);
+
+ return UWBCAPINFO_TO_N_CAPS(capinfo);
+}
+
+static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+ struct whci_card *card;
+ int err, n_caps, n;
+
+ err = pci_enable_device(pci);
+ if (err < 0)
+ goto error;
+ pci_enable_msi(pci);
+ pci_set_master(pci);
+ err = -ENXIO;
+ if (!pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
+ pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
+ else if (!pci_set_dma_mask(pci, DMA_BIT_MASK(32)))
+ pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
+ else
+ goto error_dma;
+
+ err = n_caps = whci_n_caps(pci);
+ if (n_caps < 0)
+ goto error_ncaps;
+
+ err = -ENOMEM;
+ card = kzalloc(sizeof(struct whci_card)
+ + sizeof(struct umc_dev *) * (n_caps + 1),
+ GFP_KERNEL);
+ if (card == NULL)
+ goto error_kzalloc;
+ card->pci = pci;
+ card->n_caps = n_caps;
+
+ err = -EBUSY;
+ if (!request_mem_region(pci_resource_start(pci, 0),
+ UWBCAPDATA_SIZE(card->n_caps),
+ "whci (capability data)"))
+ goto error_request_memregion;
+ err = -ENOMEM;
+ card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps));
+ if (!card->uwbbase)
+ goto error_iomap;
+
+ /* Add each capability. */
+ for (n = 0; n <= card->n_caps; n++) {
+ err = whci_add_cap(card, n);
+ if (err < 0 && n == 0) {
+ dev_err(&pci->dev, "cannot bind UWB radio controller:"
+ " %d\n", err);
+ goto error_bind;
+ }
+ if (err < 0)
+ dev_warn(&pci->dev, "warning: cannot bind capability "
+ "#%u: %d\n", n, err);
+ }
+ pci_set_drvdata(pci, card);
+ return 0;
+
+error_bind:
+ pci_iounmap(pci, card->uwbbase);
+error_iomap:
+ release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
+error_request_memregion:
+ kfree(card);
+error_kzalloc:
+error_ncaps:
+error_dma:
+ pci_disable_msi(pci);
+ pci_disable_device(pci);
+error:
+ return err;
+}
+
+static void whci_remove(struct pci_dev *pci)
+{
+ struct whci_card *card = pci_get_drvdata(pci);
+ int n;
+
+ pci_set_drvdata(pci, NULL);
+ /* Unregister each capability in reverse (so the master device
+ * is unregistered last). */
+ for (n = card->n_caps; n >= 0 ; n--)
+ whci_del_cap(card, n);
+ pci_iounmap(pci, card->uwbbase);
+ release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
+ kfree(card);
+ pci_disable_msi(pci);
+ pci_disable_device(pci);
+}
+
+static struct pci_device_id whci_id_table[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(pci, whci_id_table);
+
+
+static struct pci_driver whci_driver = {
+ .name = "whci",
+ .id_table = whci_id_table,
+ .probe = whci_probe,
+ .remove = whci_remove,
+};
+
+module_pci_driver(whci_driver);
+MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
index ea54cc27e645..d4d1e44b16b2 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
@@ -75,34 +75,27 @@ static const struct v4l2_fract
/* video formats */
static struct mmal_fmt formats[] = {
{
- .name = "4:2:0, planar, YUV",
.fourcc = V4L2_PIX_FMT_YUV420,
- .flags = 0,
.mmal = MMAL_ENCODING_I420,
.depth = 12,
.mmal_component = COMP_CAMERA,
.ybbp = 1,
.remove_padding = 1,
}, {
- .name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
- .flags = 0,
.mmal = MMAL_ENCODING_YUYV,
.depth = 16,
.mmal_component = COMP_CAMERA,
.ybbp = 2,
.remove_padding = 0,
}, {
- .name = "RGB24 (LE)",
.fourcc = V4L2_PIX_FMT_RGB24,
- .flags = 0,
.mmal = MMAL_ENCODING_RGB24,
.depth = 24,
.mmal_component = COMP_CAMERA,
.ybbp = 3,
.remove_padding = 0,
}, {
- .name = "JPEG",
.fourcc = V4L2_PIX_FMT_JPEG,
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal = MMAL_ENCODING_JPEG,
@@ -111,7 +104,6 @@ static struct mmal_fmt formats[] = {
.ybbp = 0,
.remove_padding = 0,
}, {
- .name = "H264",
.fourcc = V4L2_PIX_FMT_H264,
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal = MMAL_ENCODING_H264,
@@ -120,7 +112,6 @@ static struct mmal_fmt formats[] = {
.ybbp = 0,
.remove_padding = 0,
}, {
- .name = "MJPEG",
.fourcc = V4L2_PIX_FMT_MJPEG,
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal = MMAL_ENCODING_MJPEG,
@@ -129,72 +120,56 @@ static struct mmal_fmt formats[] = {
.ybbp = 0,
.remove_padding = 0,
}, {
- .name = "4:2:2, packed, YVYU",
.fourcc = V4L2_PIX_FMT_YVYU,
- .flags = 0,
.mmal = MMAL_ENCODING_YVYU,
.depth = 16,
.mmal_component = COMP_CAMERA,
.ybbp = 2,
.remove_padding = 0,
}, {
- .name = "4:2:2, packed, VYUY",
.fourcc = V4L2_PIX_FMT_VYUY,
- .flags = 0,
.mmal = MMAL_ENCODING_VYUY,
.depth = 16,
.mmal_component = COMP_CAMERA,
.ybbp = 2,
.remove_padding = 0,
}, {
- .name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
- .flags = 0,
.mmal = MMAL_ENCODING_UYVY,
.depth = 16,
.mmal_component = COMP_CAMERA,
.ybbp = 2,
.remove_padding = 0,
}, {
- .name = "4:2:0, planar, NV12",
.fourcc = V4L2_PIX_FMT_NV12,
- .flags = 0,
.mmal = MMAL_ENCODING_NV12,
.depth = 12,
.mmal_component = COMP_CAMERA,
.ybbp = 1,
.remove_padding = 1,
}, {
- .name = "RGB24 (BE)",
.fourcc = V4L2_PIX_FMT_BGR24,
- .flags = 0,
.mmal = MMAL_ENCODING_BGR24,
.depth = 24,
.mmal_component = COMP_CAMERA,
.ybbp = 3,
.remove_padding = 0,
}, {
- .name = "4:2:0, planar, YVU",
.fourcc = V4L2_PIX_FMT_YVU420,
- .flags = 0,
.mmal = MMAL_ENCODING_YV12,
.depth = 12,
.mmal_component = COMP_CAMERA,
.ybbp = 1,
.remove_padding = 1,
}, {
- .name = "4:2:0, planar, NV21",
.fourcc = V4L2_PIX_FMT_NV21,
- .flags = 0,
.mmal = MMAL_ENCODING_NV21,
.depth = 12,
.mmal_component = COMP_CAMERA,
.ybbp = 1,
.remove_padding = 1,
}, {
- .name = "RGB32 (BE)",
.fourcc = V4L2_PIX_FMT_BGR32,
- .flags = 0,
.mmal = MMAL_ENCODING_BGRA,
.depth = 32,
.mmal_component = COMP_CAMERA,
@@ -716,9 +691,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
fmt = &formats[f->index];
- strlcpy((char *)f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
- f->flags = fmt->flags;
return 0;
}
@@ -919,9 +892,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
fmt = &formats[f->index];
- strlcpy((char *)f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
- f->flags = fmt->flags;
return 0;
}
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
index 6f56c517d850..ff5398737b4a 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
@@ -26,7 +26,6 @@ struct mmal_msg_context;
/* mapping between v4l and mmal video modes */
struct mmal_fmt {
- char *name;
u32 fourcc; /* v4l2 format id */
int flags; /* v4l2 flags field */
u32 mmal;
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
index f738e7f99e96..47897e81ec58 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
@@ -56,7 +56,7 @@ struct vchiq_mmal_port {
/* component port belongs to, allows simple deref */
struct vchiq_mmal_component *component;
- struct vchiq_mmal_port *connected; /* port conencted to */
+ struct vchiq_mmal_port *connected; /* port connected to */
/* buffer info */
struct vchiq_mmal_port_buffer minimum_buffer;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
index 61c69f353cdb..8dc730cfe7a6 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
@@ -141,10 +141,8 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
return PTR_ERR(g_regs);
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(dev, "failed to get IRQ\n");
+ if (irq <= 0)
return irq;
- }
err = devm_request_irq(dev, irq, vchiq_doorbell_irq, IRQF_IRQPOLL,
"VCHIQ doorbell", state);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index cc4383d1ec3e..b1595b13dea8 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -2824,7 +2824,6 @@ vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service)
VCHIQ_STATUS_T ret = VCHIQ_SUCCESS;
char entity[16];
int *entity_uc;
- int local_uc, local_entity_uc;
if (!arm_state)
goto out;
@@ -2849,8 +2848,8 @@ vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service)
ret = VCHIQ_ERROR;
goto unlock;
}
- local_uc = --arm_state->videocore_use_count;
- local_entity_uc = --(*entity_uc);
+ --arm_state->videocore_use_count;
+ --(*entity_uc);
if (!vchiq_videocore_wanted(state)) {
if (vchiq_platform_use_suspend_timer() &&
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
index 183f5cf887e0..56a23a297fa4 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -3322,13 +3322,13 @@ vchiq_dump_shared_state(void *dump_context, struct vchiq_state *state,
char buf[80];
int len;
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" %s: slots %d-%d tx_pos=%x recycle=%x",
label, shared->slot_first, shared->slot_last,
shared->tx_pos, shared->slot_queue_recycle);
vchiq_dump(dump_context, buf, len + 1);
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" Slots claimed:");
vchiq_dump(dump_context, buf, len + 1);
@@ -3336,7 +3336,7 @@ vchiq_dump_shared_state(void *dump_context, struct vchiq_state *state,
struct vchiq_slot_info slot_info =
*SLOT_INFO_FROM_INDEX(state, i);
if (slot_info.use_count != slot_info.release_count) {
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" %d: %d/%d", i, slot_info.use_count,
slot_info.release_count);
vchiq_dump(dump_context, buf, len + 1);
@@ -3344,7 +3344,7 @@ vchiq_dump_shared_state(void *dump_context, struct vchiq_state *state,
}
for (i = 1; i < shared->debug[DEBUG_ENTRIES]; i++) {
- len = snprintf(buf, sizeof(buf), " DEBUG: %s = %d(%x)",
+ len = scnprintf(buf, sizeof(buf), " DEBUG: %s = %d(%x)",
debug_names[i], shared->debug[i], shared->debug[i]);
vchiq_dump(dump_context, buf, len + 1);
}
@@ -3357,11 +3357,11 @@ vchiq_dump_state(void *dump_context, struct vchiq_state *state)
int len;
int i;
- len = snprintf(buf, sizeof(buf), "State %d: %s", state->id,
+ len = scnprintf(buf, sizeof(buf), "State %d: %s", state->id,
conn_state_names[state->conn_state]);
vchiq_dump(dump_context, buf, len + 1);
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" tx_pos=%x(@%pK), rx_pos=%x(@%pK)",
state->local->tx_pos,
state->tx_data + (state->local_tx_pos & VCHIQ_SLOT_MASK),
@@ -3369,13 +3369,13 @@ vchiq_dump_state(void *dump_context, struct vchiq_state *state)
state->rx_data + (state->rx_pos & VCHIQ_SLOT_MASK));
vchiq_dump(dump_context, buf, len + 1);
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" Version: %d (min %d)",
VCHIQ_VERSION, VCHIQ_VERSION_MIN);
vchiq_dump(dump_context, buf, len + 1);
if (VCHIQ_ENABLE_STATS) {
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, "
"error_count=%d",
state->stats.ctrl_tx_count, state->stats.ctrl_rx_count,
@@ -3383,7 +3383,7 @@ vchiq_dump_state(void *dump_context, struct vchiq_state *state)
vchiq_dump(dump_context, buf, len + 1);
}
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" Slots: %d available (%d data), %d recyclable, %d stalls "
"(%d data)",
((state->slot_queue_available * VCHIQ_SLOT_SIZE) -
@@ -3416,7 +3416,7 @@ vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
char buf[80];
int len;
- len = snprintf(buf, sizeof(buf), "Service %u: %s (ref %u)",
+ len = scnprintf(buf, sizeof(buf), "Service %u: %s (ref %u)",
service->localport, srvstate_names[service->srvstate],
service->ref_count - 1); /*Don't include the lock just taken*/
@@ -3428,17 +3428,17 @@ vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
int tx_pending, rx_pending;
if (service->remoteport != VCHIQ_PORT_FREE) {
- int len2 = snprintf(remoteport, sizeof(remoteport),
+ int len2 = scnprintf(remoteport, sizeof(remoteport),
"%u", service->remoteport);
if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
- snprintf(remoteport + len2,
+ scnprintf(remoteport + len2,
sizeof(remoteport) - len2,
" (client %x)", service->client_id);
} else
strcpy(remoteport, "n/a");
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += scnprintf(buf + len, sizeof(buf) - len,
" '%c%c%c%c' remote %s (msg use %d/%d, slot use %d/%d)",
VCHIQ_FOURCC_AS_4CHARS(fourcc),
remoteport,
@@ -3455,7 +3455,7 @@ vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
rx_pending = service->bulk_rx.local_insert -
service->bulk_rx.remote_insert;
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" Bulk: tx_pending=%d (size %d),"
" rx_pending=%d (size %d)",
tx_pending,
@@ -3468,7 +3468,7 @@ vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
if (VCHIQ_ENABLE_STATS) {
vchiq_dump(dump_context, buf, len + 1);
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" Ctrl: tx_count=%d, tx_bytes=%llu, "
"rx_count=%d, rx_bytes=%llu",
service->stats.ctrl_tx_count,
@@ -3477,7 +3477,7 @@ vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
service->stats.ctrl_rx_bytes);
vchiq_dump(dump_context, buf, len + 1);
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" Bulk: tx_count=%d, tx_bytes=%llu, "
"rx_count=%d, rx_bytes=%llu",
service->stats.bulk_tx_count,
@@ -3486,7 +3486,7 @@ vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
service->stats.bulk_rx_bytes);
vchiq_dump(dump_context, buf, len + 1);
- len = snprintf(buf, sizeof(buf),
+ len = scnprintf(buf, sizeof(buf),
" %d quota stalls, %d slot stalls, "
"%d bulk stalls, %d aborted, %d errors",
service->stats.quota_stalls,
@@ -3562,9 +3562,9 @@ void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem,
for (offset = 0; offset < 16; offset++) {
if (offset < num_bytes)
- s += snprintf(s, 4, "%02x ", mem[offset]);
+ s += scnprintf(s, 4, "%02x ", mem[offset]);
else
- s += snprintf(s, 4, " ");
+ s += scnprintf(s, 4, " ");
}
for (offset = 0; offset < 16; offset++) {
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index 9def0748ffee..4e9cfacf75f2 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -287,12 +287,12 @@ static u16 vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context,
buf->duration_a = vnt_get_duration_le(priv,
tx_context->pkt_type, need_ack);
buf->duration_b = vnt_get_duration_le(priv,
- PK_TYPE_11B, need_ack);
+ PK_TYPE_11B, need_ack);
}
buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate);
buf->time_stamp_off_b = vnt_time_stamp_off(priv,
- priv->top_cck_basic_rate);
+ priv->top_cck_basic_rate);
tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr);
@@ -325,7 +325,7 @@ static u16 vnt_rxtx_datahead_g_fb(struct vnt_usb_send_context *tx_context,
buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate);
buf->time_stamp_off_b = vnt_time_stamp_off(priv,
- priv->top_cck_basic_rate);
+ priv->top_cck_basic_rate);
tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr);
@@ -655,7 +655,7 @@ static u16 vnt_rxtx_ab(struct vnt_usb_send_context *tx_context,
u8 need_ack = tx_context->need_ack;
buf->rrv_time = vnt_rxtx_rsvtime_le16(priv, tx_context->pkt_type,
- frame_len, current_rate, need_ack);
+ frame_len, current_rate, need_ack);
if (need_mic)
head = &tx_head->tx_ab.tx.mic.head;
@@ -1036,7 +1036,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, struct sk_buff *skb)
/* Get Duration and TimeStampOff */
short_head->duration = vnt_get_duration_le(priv,
- PK_TYPE_11B, false);
+ PK_TYPE_11B, false);
short_head->time_stamp_off =
vnt_time_stamp_off(priv, current_rate);
}
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index ff351a7a0876..d3304df6bd53 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -216,7 +216,7 @@ static void vnt_submit_rx_urb_complete(struct urb *urb)
}
urb->transfer_buffer = skb_put(rcb->skb,
- skb_tailroom(rcb->skb));
+ skb_tailroom(rcb->skb));
}
if (usb_submit_urb(urb, GFP_ATOMIC)) {
diff --git a/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt b/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt
index 4f7d1c2be4d0..da5235950a70 100644
--- a/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt
+++ b/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt
@@ -10,7 +10,9 @@ Required properties:
Optional:
- bus-width : Number of data lines wired up the slot. Default 1 bit.
-
+- rtc_clk : Clock connected on the rtc clock line. Must be assigned
+ a frequency with assigned-clocks property, and must be
+ connected to a clock provider.
Examples:
mmc1: mmc@fc000000 {
@@ -24,6 +26,10 @@ mmc1: mmc@fc000000 {
wilc_sdio@0 {
compatible = "microchip,wilc1000-sdio";
irq-gpios = <&pioC 27 0>;
+ clocks = <&pck1>;
+ clock-names = "rtc_clk";
+ assigned-clocks = <&pck1>;
+ assigned-clock-rates = <32768>;
status = "okay";
reg = <0>;
bus-width = <4>;
diff --git a/drivers/staging/wilc1000/microchip,wilc1000,spi.txt b/drivers/staging/wilc1000/microchip,wilc1000,spi.txt
index 87db87b2d901..34236932dbb6 100644
--- a/drivers/staging/wilc1000/microchip,wilc1000,spi.txt
+++ b/drivers/staging/wilc1000/microchip,wilc1000,spi.txt
@@ -9,6 +9,10 @@ Required properties:
- reg : Chip select address of device
- irq-gpios : Connect to a host IRQ
+Optional:
+- rtc_clk : Clock connected on the rtc clock line. Must be assigned
+ a frequency with assigned-clocks property, and must be
+ connected to a clock provider.
Examples:
@@ -21,6 +25,10 @@ spi1: spi@fc018000 {
spi-max-frequency = <48000000>;
reg = <0>;
irq-gpios = <&pioC 27 0>;
+ clocks = <&pck1>;
+ clock-names = "rtc_clk";
+ assigned-clocks = <&pck1>;
+ assigned-clock-rates = <32768>;
status = "okay";
};
};
diff --git a/drivers/staging/wilc1000/wilc_hif.c b/drivers/staging/wilc1000/wilc_hif.c
index 9345cabe3c93..f2b7d5a1be17 100644
--- a/drivers/staging/wilc1000/wilc_hif.c
+++ b/drivers/staging/wilc1000/wilc_hif.c
@@ -248,7 +248,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
goto error;
}
- if (vif->obtaining_ip || vif->connecting) {
+ if (vif->connecting) {
netdev_err(vif->ndev, "Don't do obss scan\n");
result = -EBUSY;
goto error;
@@ -679,13 +679,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
if (mac_status == WILC_MAC_STATUS_CONNECTED &&
conn_info->status == WLAN_STATUS_SUCCESS) {
ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);
- wilc_set_power_mgmt(vif, 0, 0);
-
hif_drv->hif_state = HOST_IF_CONNECTED;
-
- vif->obtaining_ip = true;
- mod_timer(&vif->during_ip_timer,
- jiffies + msecs_to_jiffies(10000));
} else {
hif_drv->hif_state = HOST_IF_IDLE;
}
@@ -708,15 +702,11 @@ static inline void host_int_handle_disconnect(struct wilc_vif *vif)
handle_scan_done(vif, SCAN_EVENT_ABORTED);
}
- if (hif_drv->conn_info.conn_result) {
- vif->obtaining_ip = false;
- wilc_set_power_mgmt(vif, 0, 0);
-
+ if (hif_drv->conn_info.conn_result)
hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
0, hif_drv->conn_info.arg);
- } else {
+ else
netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
- }
eth_zero_addr(hif_drv->assoc_bssid);
@@ -772,9 +762,6 @@ int wilc_disconnect(struct wilc_vif *vif)
wid.val = (s8 *)&dummy_reason_code;
wid.size = sizeof(char);
- vif->obtaining_ip = false;
- wilc_set_power_mgmt(vif, 0, 0);
-
result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result) {
netdev_err(vif->ndev, "Failed to send disconnect\n");
@@ -811,15 +798,6 @@ int wilc_disconnect(struct wilc_vif *vif)
return 0;
}
-void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
-{
- if (!vif->hif_drv)
- return;
- if (vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
- vif->hif_drv->hif_state == HOST_IF_CONNECTING)
- wilc_disconnect(vif);
-}
-
int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
{
struct wid wid_list[5];
@@ -924,7 +902,7 @@ static int handle_remain_on_chan(struct wilc_vif *vif,
if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
return -EBUSY;
- if (vif->obtaining_ip || vif->connecting)
+ if (vif->connecting)
return -EBUSY;
remain_on_chan_flag = true;
@@ -1069,13 +1047,9 @@ static void handle_scan_timer(struct work_struct *work)
static void handle_scan_complete(struct work_struct *work)
{
struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
- struct wilc *wilc = msg->vif->wilc;
del_timer(&msg->vif->hif_drv->scan_timer);
- if (!wilc_wlan_get_num_conn_ifcs(wilc))
- wilc_chip_sleep_manually(wilc);
-
handle_scan_done(msg->vif, SCAN_EVENT_DONE);
kfree(msg);
@@ -1426,18 +1400,14 @@ int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
return result;
}
-int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
- u8 ifc_id)
+int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id)
{
struct wid wid;
- struct host_if_drv *hif_drv = vif->hif_drv;
int result;
struct wilc_drv_handler drv;
- if (!hif_drv)
- return -EFAULT;
-
- wid.id = WID_SET_DRV_HANDLER;
+ wid.id = WID_SET_OPERATION_MODE;
wid.type = WID_STR;
wid.size = sizeof(drv);
wid.val = (u8 *)&drv;
@@ -1452,26 +1422,6 @@ int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
return result;
}
-int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
-{
- struct wid wid;
- struct wilc_op_mode op_mode;
- int result;
-
- wid.id = WID_SET_OPERATION_MODE;
- wid.type = WID_INT;
- wid.size = sizeof(op_mode);
- wid.val = (u8 *)&op_mode;
-
- op_mode.mode = cpu_to_le32(mode);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to set operation mode\n");
-
- return result;
-}
-
s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
{
struct wid wid;
@@ -1610,7 +1560,6 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
*hif_drv_handler = hif_drv;
vif->hif_drv = hif_drv;
- vif->obtaining_ip = false;
if (wilc->clients_count == 0)
mutex_init(&wilc->deinit_lock);
@@ -1648,8 +1597,6 @@ int wilc_deinit(struct wilc_vif *vif)
del_timer_sync(&vif->periodic_rssi);
del_timer_sync(&hif_drv->remain_on_ch_timer);
- wilc_set_wfi_drv_handler(vif, 0, 0, 0);
-
if (hif_drv->usr_scan_req.scan_result) {
hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
hif_drv->usr_scan_req.arg);
@@ -2024,9 +1971,6 @@ int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
int result;
s8 power_mode;
- if (wilc_wlan_get_num_conn_ifcs(vif->wilc) == 2 && enabled)
- return 0;
-
if (enabled)
power_mode = WILC_FW_MIN_FAST_PS;
else
diff --git a/drivers/staging/wilc1000/wilc_hif.h b/drivers/staging/wilc1000/wilc_hif.h
index be1d2497cde9..ac5fe57f872b 100644
--- a/drivers/staging/wilc1000/wilc_hif.h
+++ b/drivers/staging/wilc1000/wilc_hif.h
@@ -219,11 +219,9 @@ int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
void *user_arg);
int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
-int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
- u8 ifc_id);
-int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode);
+int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id);
int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
-void wilc_resolve_disconnect_aberration(struct wilc_vif *vif);
int wilc_get_vif_idx(struct wilc_vif *vif);
int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
diff --git a/drivers/staging/wilc1000/wilc_mon.c b/drivers/staging/wilc1000/wilc_mon.c
index 7d7933d40924..d6f14f69ad64 100644
--- a/drivers/staging/wilc1000/wilc_mon.c
+++ b/drivers/staging/wilc1000/wilc_mon.c
@@ -35,8 +35,7 @@ void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size)
return;
/* Get WILC header */
- memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
- le32_to_cpus(&header);
+ header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
/*
* The packet offset field contain info about what type of management
* the frame we are dealing with and ack status
diff --git a/drivers/staging/wilc1000/wilc_netdev.c b/drivers/staging/wilc1000/wilc_netdev.c
index 565e2b5d0616..508acb8bb089 100644
--- a/drivers/staging/wilc1000/wilc_netdev.c
+++ b/drivers/staging/wilc1000/wilc_netdev.c
@@ -11,6 +11,7 @@
#include <linux/inetdevice.h>
#include "wilc_wfi_cfgoperations.h"
+#include "wilc_wlan_cfg.h"
#define WILC_MULTICAST_TABLE_SIZE 8
@@ -59,7 +60,7 @@ static int init_irq(struct net_device *dev)
ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine,
isr_bh_routine,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"WILC_IRQ", dev);
if (ret < 0)
netdev_err(dev, "Failed to request IRQ\n");
@@ -474,7 +475,7 @@ static void wilc_wlan_deinitialize(struct net_device *dev)
wlan_deinitialize_threads(dev);
deinit_irq(dev);
- wilc_wlan_stop(wl);
+ wilc_wlan_stop(wl, vif);
wilc_wlan_cleanup(dev);
wlan_deinit_locks(dev);
@@ -503,12 +504,6 @@ static int wlan_initialize_threads(struct net_device *dev)
return 0;
}
-static int dev_state_ev_handler(struct notifier_block *this,
- unsigned long event, void *ptr);
-static struct notifier_block g_dev_notifier = {
- .notifier_call = dev_state_ev_handler
-};
-
static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
{
int ret = 0;
@@ -574,12 +569,11 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
ret = -EIO;
goto fail_fw_start;
}
- register_inetaddr_notifier(&g_dev_notifier);
wl->initialized = true;
return 0;
fail_fw_start:
- wilc_wlan_stop(wl);
+ wilc_wlan_stop(wl, vif);
fail_irq_enable:
if (!wl->dev_irq_num &&
@@ -632,10 +626,8 @@ static int wilc_mac_open(struct net_device *ndev)
return ret;
}
- wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), vif->iftype,
- vif->idx);
- wilc_set_operation_mode(vif, vif->iftype);
-
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype,
+ vif->idx);
wilc_get_mac_address(vif, mac_add);
netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
ether_addr_copy(ndev->dev_addr, mac_add);
@@ -780,7 +772,6 @@ static int wilc_mac_close(struct net_device *ndev)
if (wl->open_ifcs == 0) {
netdev_dbg(ndev, "Deinitializing wilc1000\n");
wl->close = 1;
- unregister_inetaddr_notifier(&g_dev_notifier);
wilc_wlan_deinitialize(ndev);
}
@@ -863,63 +854,6 @@ static const struct net_device_ops wilc_netdev_ops = {
.ndo_set_rx_mode = wilc_set_multicast_list,
};
-static int dev_state_ev_handler(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct in_ifaddr *dev_iface = ptr;
- struct wilc_priv *priv;
- struct host_if_drv *hif_drv;
- struct net_device *dev;
- struct wilc_vif *vif;
-
- if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev)
- return NOTIFY_DONE;
-
- dev = (struct net_device *)dev_iface->ifa_dev->dev;
- if (dev->netdev_ops != &wilc_netdev_ops)
- return NOTIFY_DONE;
-
- if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
- return NOTIFY_DONE;
-
- vif = netdev_priv(dev);
- priv = &vif->priv;
-
- hif_drv = (struct host_if_drv *)priv->hif_drv;
-
- switch (event) {
- case NETDEV_UP:
- if (vif->iftype == WILC_STATION_MODE ||
- vif->iftype == WILC_CLIENT_MODE) {
- hif_drv->ifc_up = 1;
- vif->obtaining_ip = false;
- del_timer(&vif->during_ip_timer);
- }
-
- if (vif->wilc->enable_ps)
- wilc_set_power_mgmt(vif, 1, 0);
-
- break;
-
- case NETDEV_DOWN:
- if (vif->iftype == WILC_STATION_MODE ||
- vif->iftype == WILC_CLIENT_MODE) {
- hif_drv->ifc_up = 0;
- vif->obtaining_ip = false;
- wilc_set_power_mgmt(vif, 0, 0);
- }
-
- wilc_resolve_disconnect_aberration(vif);
-
- break;
-
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
void wilc_netdev_cleanup(struct wilc *wilc)
{
int i;
diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
index 4c1c81fed11f..c787c5da8f2b 100644
--- a/drivers/staging/wilc1000/wilc_sdio.c
+++ b/drivers/staging/wilc1000/wilc_sdio.c
@@ -4,6 +4,7 @@
* All rights reserved.
*/
+#include <linux/clk.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/host.h>
@@ -151,6 +152,12 @@ static int wilc_sdio_probe(struct sdio_func *func,
wilc->dev = &func->dev;
wilc->gpio_irq = gpio;
+ wilc->rtc_clk = devm_clk_get(&func->card->dev, "rtc_clk");
+ if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else if (!IS_ERR(wilc->rtc_clk))
+ clk_prepare_enable(wilc->rtc_clk);
+
dev_info(&func->dev, "Driver Initializing success\n");
return 0;
}
@@ -162,6 +169,10 @@ static void wilc_sdio_remove(struct sdio_func *func)
/* free the GPIO in module remove */
if (wilc->gpio_irq)
gpiod_put(wilc->gpio_irq);
+
+ if (!IS_ERR(wilc->rtc_clk))
+ clk_disable_unprepare(wilc->rtc_clk);
+
wilc_netdev_cleanup(wilc);
}
@@ -193,9 +204,10 @@ static int wilc_sdio_suspend(struct device *dev)
dev_info(dev, "sdio suspend\n");
chip_wakeup(wilc);
- if (!wilc->suspend_event) {
- wilc_chip_sleep_manually(wilc);
- } else {
+ if (!IS_ERR(wilc->rtc_clk))
+ clk_disable_unprepare(wilc->rtc_clk);
+
+ if (wilc->suspend_event) {
host_sleep_notify(wilc);
chip_allow_sleep(wilc);
}
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
index 736eedef23b6..22f21831649b 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
@@ -70,15 +70,6 @@ struct wilc_p2p_mgmt_data {
static const u8 p2p_oui[] = {0x50, 0x6f, 0x9A, 0x09};
static const u8 p2p_vendor_spec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03};
-#define WILC_IP_TIMEOUT_MS 15000
-
-static void clear_during_ip(struct timer_list *t)
-{
- struct wilc_vif *vif = from_timer(vif, t, during_ip_timer);
-
- vif->obtaining_ip = false;
-}
-
static void cfg_scan_result(enum scan_event scan_event,
struct wilc_rcvd_net_info *info, void *user_void)
{
@@ -176,7 +167,6 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
} else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
u16 reason = 0;
- vif->obtaining_ip = false;
priv->p2p.local_random = 0x01;
priv->p2p.recv_random = 0x00;
priv->p2p.is_wilc_ie = false;
@@ -1038,8 +1028,7 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
s32 freq;
__le16 fc;
- memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
- le32_to_cpus(&header);
+ header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
pkt_offset = GET_PKT_OFFSET(header);
if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
@@ -1404,8 +1393,7 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
if (!priv->hif_drv)
return -EIO;
- if (vif->wilc->enable_ps)
- wilc_set_power_mgmt(vif, enabled, timeout);
+ wilc_set_power_mgmt(vif, enabled, timeout);
return 0;
}
@@ -1421,8 +1409,6 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
priv->p2p.local_random = 0x01;
priv->p2p.recv_random = 0x00;
priv->p2p.is_wilc_ie = false;
- vif->obtaining_ip = false;
- del_timer(&vif->during_ip_timer);
switch (type) {
case NL80211_IFTYPE_STATION:
@@ -1433,13 +1419,11 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)
wilc_wfi_deinit_mon_interface(wl, true);
vif->iftype = WILC_STATION_MODE;
- wilc_set_operation_mode(vif, WILC_STATION_MODE);
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_STATION_MODE, vif->idx);
memset(priv->assoc_stainfo.sta_associated_bss, 0,
WILC_MAX_NUM_STA * ETH_ALEN);
-
- wl->enable_ps = true;
- wilc_set_power_mgmt(vif, 1, 0);
break;
case NL80211_IFTYPE_P2P_CLIENT:
@@ -1448,37 +1432,26 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
priv->wdev.iftype = type;
vif->monitor_flag = 0;
vif->iftype = WILC_CLIENT_MODE;
- wilc_set_operation_mode(vif, WILC_STATION_MODE);
-
- wl->enable_ps = false;
- wilc_set_power_mgmt(vif, 0, 0);
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_STATION_MODE, vif->idx);
break;
case NL80211_IFTYPE_AP:
- wl->enable_ps = false;
dev->ieee80211_ptr->iftype = type;
priv->wdev.iftype = type;
vif->iftype = WILC_AP_MODE;
- if (wl->initialized) {
- wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
- 0, vif->idx);
- wilc_set_operation_mode(vif, WILC_AP_MODE);
- wilc_set_power_mgmt(vif, 0, 0);
- }
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_AP_MODE, vif->idx);
break;
case NL80211_IFTYPE_P2P_GO:
- vif->obtaining_ip = true;
- mod_timer(&vif->during_ip_timer,
- jiffies + msecs_to_jiffies(WILC_IP_TIMEOUT_MS));
- wilc_set_operation_mode(vif, WILC_AP_MODE);
dev->ieee80211_ptr->iftype = type;
priv->wdev.iftype = type;
vif->iftype = WILC_GO_MODE;
-
- wl->enable_ps = false;
- wilc_set_power_mgmt(vif, 0, 0);
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_AP_MODE, vif->idx);
break;
default:
@@ -1500,7 +1473,6 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
netdev_err(dev, "Error in setting channel\n");
wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE);
- wilc_set_power_mgmt(vif, 0, 0);
return wilc_add_beacon(vif, settings->beacon_interval,
settings->dtim_period, &settings->beacon);
@@ -1687,16 +1659,16 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
vif->monitor_flag = 0;
mutex_lock(&wl->vif_mutex);
- wilc_set_wfi_drv_handler(vif, 0, 0, 0);
- for (i = vif->idx; i < wl->vif_num ; i++) {
+ wilc_set_operation_mode(vif, 0, 0, 0);
+ for (i = vif->idx; i < wl->vif_num; i++) {
if ((i + 1) >= wl->vif_num) {
wl->vif[i] = NULL;
} else {
vif = wl->vif[i + 1];
vif->idx = i;
wl->vif[i] = vif;
- wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
- vif->iftype, vif->idx);
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ vif->iftype, vif->idx);
}
}
wl->vif_num--;
@@ -1851,7 +1823,6 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
*wilc = wl;
wl->io_type = io_type;
wl->hif_func = ops;
- wl->enable_ps = false;
wl->chip_ps_state = WILC_CHIP_WAKEDUP;
INIT_LIST_HEAD(&wl->txq_head.list);
INIT_LIST_HEAD(&wl->rxq_head.list);
@@ -1949,8 +1920,6 @@ int wilc_init_host_int(struct net_device *net)
struct wilc_vif *vif = netdev_priv(net);
struct wilc_priv *priv = &vif->priv;
- timer_setup(&vif->during_ip_timer, clear_during_ip, 0);
-
priv->p2p_listen_state = false;
mutex_init(&priv->scan_req_lock);
@@ -1973,8 +1942,6 @@ void wilc_deinit_host_int(struct net_device *net)
mutex_destroy(&priv->scan_req_lock);
ret = wilc_deinit(vif);
- del_timer_sync(&vif->during_ip_timer);
-
if (ret)
netdev_err(net, "Error while deinitializing host interface\n");
}
diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
index 1e74a08e7cf1..978a8bdbfc40 100644
--- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h
+++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
@@ -203,7 +203,6 @@ struct wilc_vif {
struct net_device *ndev;
u8 mode;
struct timer_list during_ip_timer;
- bool obtaining_ip;
struct timer_list periodic_rssi;
struct rf_info periodic_stat;
struct tcp_ack_filter ack_filter;
@@ -217,6 +216,7 @@ struct wilc {
int io_type;
s8 mac_status;
struct gpio_desc *gpio_irq;
+ struct clk *rtc_clk;
bool initialized;
int dev_irq_num;
int close;
@@ -262,7 +262,6 @@ struct wilc {
struct device *dev;
bool suspend_event;
- bool enable_ps;
int clients_count;
struct workqueue_struct *hif_workqueue;
enum chip_ps_states chip_ps_state;
diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c
index d46876edcfeb..771d8cb68dc1 100644
--- a/drivers/staging/wilc1000/wilc_wlan.c
+++ b/drivers/staging/wilc1000/wilc_wlan.c
@@ -455,20 +455,6 @@ void chip_wakeup(struct wilc *wilc)
}
EXPORT_SYMBOL_GPL(chip_wakeup);
-void wilc_chip_sleep_manually(struct wilc *wilc)
-{
- if (wilc->chip_ps_state != WILC_CHIP_WAKEDUP)
- return;
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
-
- chip_allow_sleep(wilc);
- wilc->hif_func->hif_write_reg(wilc, 0x10a8, 1);
-
- wilc->chip_ps_state = WILC_CHIP_SLEEPING_MANUAL;
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
-}
-EXPORT_SYMBOL_GPL(wilc_chip_sleep_manually);
-
void host_wakeup_notify(struct wilc *wilc)
{
acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
@@ -703,8 +689,7 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
do {
buff_ptr = buffer + offset;
- memcpy(&header, buff_ptr, 4);
- le32_to_cpus(&header);
+ header = get_unaligned_le32(buff_ptr);
is_cfg_packet = (header >> 31) & 0x1;
pkt_offset = (header >> 22) & 0x1ff;
@@ -773,26 +758,6 @@ static void wilc_unknown_isr_ext(struct wilc *wilc)
wilc->hif_func->hif_clear_int_ext(wilc, 0);
}
-static void wilc_pllupdate_isr_ext(struct wilc *wilc, u32 int_stats)
-{
- int trials = 10;
-
- wilc->hif_func->hif_clear_int_ext(wilc, PLL_INT_CLR);
-
- if (wilc->io_type == WILC_HIF_SDIO)
- mdelay(WILC_PLL_TO_SDIO);
- else
- mdelay(WILC_PLL_TO_SPI);
-
- while (!(is_wilc1000(wilc_get_chipid(wilc, true)) && --trials))
- mdelay(1);
-}
-
-static void wilc_sleeptimer_isr_ext(struct wilc *wilc, u32 int_stats1)
-{
- wilc->hif_func->hif_clear_int_ext(wilc, SLEEP_INT_CLR);
-}
-
static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
{
u32 offset = wilc->rx_buffer_offset;
@@ -842,15 +807,9 @@ void wilc_handle_isr(struct wilc *wilc)
acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
wilc->hif_func->hif_read_int(wilc, &int_status);
- if (int_status & PLL_INT_EXT)
- wilc_pllupdate_isr_ext(wilc, int_status);
-
if (int_status & DATA_INT_EXT)
wilc_wlan_handle_isr_ext(wilc, int_status);
- if (int_status & SLEEP_INT_EXT)
- wilc_sleeptimer_isr_ext(wilc, int_status);
-
if (!(int_status & (ALL_INT_EXT)))
wilc_unknown_isr_ext(wilc);
@@ -874,10 +833,8 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
offset = 0;
do {
- memcpy(&addr, &buffer[offset], 4);
- memcpy(&size, &buffer[offset + 4], 4);
- le32_to_cpus(&addr);
- le32_to_cpus(&size);
+ addr = get_unaligned_le32(&buffer[offset]);
+ size = get_unaligned_le32(&buffer[offset + 4]);
acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
offset += 8;
while (((int)size) && (offset < buffer_size)) {
@@ -985,72 +942,52 @@ int wilc_wlan_start(struct wilc *wilc)
return (ret < 0) ? ret : 0;
}
-int wilc_wlan_stop(struct wilc *wilc)
+int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
{
u32 reg = 0;
int ret;
- u8 timeout = 10;
acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
- ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, &reg);
if (!ret) {
+ netdev_err(vif->ndev, "Error while reading reg\n");
release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return ret;
+ return -EIO;
}
- reg &= ~BIT(10);
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
+ (reg | WILC_ABORT_REQ_BIT));
if (!ret) {
+ netdev_err(vif->ndev, "Error while writing reg\n");
release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return ret;
+ return -EIO;
}
- do {
- ret = wilc->hif_func->hif_read_reg(wilc,
- WILC_GLB_RESET_0, &reg);
- if (!ret) {
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return ret;
- }
-
- if ((reg & BIT(10))) {
- reg &= ~BIT(10);
- ret = wilc->hif_func->hif_write_reg(wilc,
- WILC_GLB_RESET_0,
- reg);
- timeout--;
- } else {
- ret = wilc->hif_func->hif_read_reg(wilc,
- WILC_GLB_RESET_0,
- &reg);
- if (!ret) {
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return ret;
- }
- break;
- }
-
- } while (timeout);
- reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) |
- BIT(29) | BIT(30) | BIT(31));
-
- wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
- reg = (u32)~BIT(10);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, &reg);
+ if (!ret) {
+ netdev_err(vif->ndev, "Error while reading reg\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return -EIO;
+ }
+ reg = BIT(0);
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg);
+ if (!ret) {
+ netdev_err(vif->ndev, "Error while writing reg\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return -EIO;
+ }
release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return ret;
+ return 0;
}
void wilc_wlan_cleanup(struct net_device *dev)
{
struct txq_entry_t *tqe;
struct rxq_entry_t *rqe;
- u32 reg = 0;
- int ret;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
@@ -1075,23 +1012,6 @@ void wilc_wlan_cleanup(struct net_device *dev)
wilc->rx_buffer = NULL;
kfree(wilc->tx_buffer);
wilc->tx_buffer = NULL;
-
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
-
- ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, &reg);
- if (!ret) {
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return;
- }
-
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
- (reg | ABORT_INT));
- if (!ret) {
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return;
- }
-
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
wilc->hif_func->hif_deinit(NULL);
}
@@ -1196,11 +1116,6 @@ int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
return ret_size;
}
-int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size)
-{
- return wilc_wlan_cfg_get_wid_value(wl, wid, buffer, buffer_size);
-}
-
int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
u32 count)
{
diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h
index d2eef7b4c3b7..7469fa47d588 100644
--- a/drivers/staging/wilc1000/wilc_wlan.h
+++ b/drivers/staging/wilc1000/wilc_wlan.h
@@ -98,6 +98,7 @@
#define WILC_VMM_TBL_RX_SHADOW_BASE WILC_AHB_SHARE_MEM_BASE
#define WILC_VMM_TBL_RX_SHADOW_SIZE 256
+#define WILC_FW_HOST_COMM 0x13c0
#define WILC_GP_REG_0 0x149c
#define WILC_GP_REG_1 0x14a0
@@ -127,9 +128,7 @@
#define WILC_CFG_RSP_STATUS 2
#define WILC_CFG_RSP_SCAN 3
-#define WILC_PLL_TO_SDIO 4
-#define WILC_PLL_TO_SPI 2
-#define ABORT_INT BIT(31)
+#define WILC_ABORT_REQ_BIT BIT(31)
#define WILC_RX_BUFF_SIZE (96 * 1024)
#define WILC_TX_BUFF_SIZE (64 * 1024)
@@ -184,14 +183,10 @@
#define EN_VMM BIT(8)
#define DATA_INT_EXT INT_0
-#define PLL_INT_EXT INT_1
-#define SLEEP_INT_EXT INT_2
-#define ALL_INT_EXT (DATA_INT_EXT | PLL_INT_EXT | SLEEP_INT_EXT)
-#define NUM_INT_EXT 3
+#define ALL_INT_EXT DATA_INT_EXT
+#define NUM_INT_EXT 1
#define DATA_INT_CLR CLR_INT0
-#define PLL_INT_CLR CLR_INT1
-#define SLEEP_INT_CLR CLR_INT2
#define ENABLE_RX_VMM (SEL_VMM_TBL1 | EN_VMM)
#define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM)
@@ -280,7 +275,7 @@ struct wilc_vif;
int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
u32 buffer_size);
int wilc_wlan_start(struct wilc *wilc);
-int wilc_wlan_stop(struct wilc *wilc);
+int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif);
int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
u32 buffer_size,
void (*tx_complete_fn)(void *, int));
@@ -291,12 +286,8 @@ int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
u32 buffer_size, int commit, u32 drv_handler);
int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
u32 drv_handler);
-int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer,
- u32 buffer_size);
int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
u32 buffer_size, void (*func)(void *, int));
-void wilc_chip_sleep_manually(struct wilc *wilc);
-
void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value);
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc);
netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c
index 9dc5de4eb08d..3f53807cee0f 100644
--- a/drivers/staging/wilc1000/wilc_wlan_cfg.c
+++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c
@@ -52,57 +52,35 @@ static const struct wilc_cfg_str g_cfg_str[] = {
static int wilc_wlan_cfg_set_byte(u8 *frame, u32 offset, u16 id, u8 val8)
{
- u8 *buf;
-
if ((offset + 4) >= WILC_MAX_CFG_FRAME_SIZE)
return 0;
- buf = &frame[offset];
-
- buf[0] = (u8)id;
- buf[1] = (u8)(id >> 8);
- buf[2] = 1;
- buf[3] = 0;
- buf[4] = val8;
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(1, &frame[offset + 2]);
+ frame[offset + 4] = val8;
return 5;
}
static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16)
{
- u8 *buf;
-
if ((offset + 5) >= WILC_MAX_CFG_FRAME_SIZE)
return 0;
- buf = &frame[offset];
-
- buf[0] = (u8)id;
- buf[1] = (u8)(id >> 8);
- buf[2] = 2;
- buf[3] = 0;
- buf[4] = (u8)val16;
- buf[5] = (u8)(val16 >> 8);
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(2, &frame[offset + 2]);
+ put_unaligned_le16(val16, &frame[offset + 4]);
return 6;
}
static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
{
- u8 *buf;
-
if ((offset + 7) >= WILC_MAX_CFG_FRAME_SIZE)
return 0;
- buf = &frame[offset];
-
- buf[0] = (u8)id;
- buf[1] = (u8)(id >> 8);
- buf[2] = 4;
- buf[3] = 0;
- buf[4] = (u8)val32;
- buf[5] = (u8)(val32 >> 8);
- buf[6] = (u8)(val32 >> 16);
- buf[7] = (u8)(val32 >> 24);
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(4, &frame[offset + 2]);
+ put_unaligned_le32(val32, &frame[offset + 4]);
return 8;
}
@@ -110,46 +88,35 @@ static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
u32 size)
{
- u8 *buf;
-
if ((offset + size + 4) >= WILC_MAX_CFG_FRAME_SIZE)
return 0;
- buf = &frame[offset];
-
- buf[0] = (u8)id;
- buf[1] = (u8)(id >> 8);
- buf[2] = (u8)size;
- buf[3] = (u8)(size >> 8);
-
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(size, &frame[offset + 2]);
if (str && size != 0)
- memcpy(&buf[4], str, size);
+ memcpy(&frame[offset + 4], str, size);
return (size + 4);
}
static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size)
{
- u8 *buf;
u32 i;
u8 checksum = 0;
if ((offset + size + 5) >= WILC_MAX_CFG_FRAME_SIZE)
return 0;
- buf = &frame[offset];
- buf[0] = (u8)id;
- buf[1] = (u8)(id >> 8);
- buf[2] = (u8)size;
- buf[3] = (u8)(size >> 8);
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(size, &frame[offset + 2]);
if ((b) && size != 0) {
- memcpy(&buf[4], b, size);
+ memcpy(&frame[offset + 4], b, size);
for (i = 0; i < size; i++)
- checksum += buf[i + 4];
+ checksum += frame[offset + i + 4];
}
- buf[size + 4] = checksum;
+ frame[offset + size + 4] = checksum;
return (size + 5);
}
@@ -307,21 +274,16 @@ int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size)
int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id)
{
- u8 *buf;
-
if ((offset + 2) >= WILC_MAX_CFG_FRAME_SIZE)
return 0;
- buf = &frame[offset];
-
- buf[0] = (u8)id;
- buf[1] = (u8)(id >> 8);
+ put_unaligned_le16(id, &frame[offset]);
return 2;
}
-int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer,
- u32 buffer_size)
+int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer,
+ u32 buffer_size)
{
u32 type = (wid >> 12) & 0xf;
int i, ret = 0;
diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.h b/drivers/staging/wilc1000/wilc_wlan_cfg.h
index e5ca6cea0682..614c5673f232 100644
--- a/drivers/staging/wilc1000/wilc_wlan_cfg.h
+++ b/drivers/staging/wilc1000/wilc_wlan_cfg.h
@@ -44,8 +44,8 @@ struct wilc_cfg {
struct wilc;
int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size);
int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id);
-int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer,
- u32 buffer_size);
+int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer,
+ u32 buffer_size);
void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
struct wilc_cfg_rsp *rsp);
int wilc_wlan_cfg_init(struct wilc *wl);
diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h
index b89d0e0f04cc..70eac586f80c 100644
--- a/drivers/staging/wilc1000/wilc_wlan_if.h
+++ b/drivers/staging/wilc1000/wilc_wlan_if.h
@@ -724,7 +724,6 @@ enum {
/* NMAC Integer WID list */
/* Custom Integer WID list */
WID_GET_INACTIVE_TIME = 0x2084,
- WID_SET_OPERATION_MODE = 0X2086,
/* EMAC String WID list */
WID_SSID = 0x3000,
WID_FIRMWARE_VERSION = 0x3001,
@@ -755,9 +754,9 @@ enum {
WID_MODEL_NAME = 0x3027, /*Added for CAPI tool */
WID_MODEL_NUM = 0x3028, /*Added for CAPI tool */
WID_DEVICE_NAME = 0x3029, /*Added for CAPI tool */
- WID_SET_DRV_HANDLER = 0x3079,
/* NMAC String WID list */
+ WID_SET_OPERATION_MODE = 0x3079,
WID_11N_P_ACTION_REQ = 0x3080,
WID_HUT_TEST_ID = 0x3081,
WID_PMKID_INFO = 0x3082,
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index ab734534093b..28d372a0663a 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -226,11 +226,9 @@ usbctlx_get_rridresult(const struct hfa384x_usb_rridresp *rridresp,
/*---------------------------------------------------*/
/* Low level req/resp CTLX formatters and submitters */
-static int
+static inline int
hfa384x_docmd(struct hfa384x *hw,
- enum cmd_mode mode,
- struct hfa384x_metacmd *cmd,
- ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data);
+ struct hfa384x_metacmd *cmd);
static int
hfa384x_dorrid(struct hfa384x *hw,
@@ -250,21 +248,17 @@ hfa384x_dowrid(struct hfa384x *hw,
static int
hfa384x_dormem(struct hfa384x *hw,
- enum cmd_mode mode,
u16 page,
u16 offset,
void *data,
- unsigned int len,
- ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data);
+ unsigned int len);
static int
hfa384x_dowmem(struct hfa384x *hw,
- enum cmd_mode mode,
u16 page,
u16 offset,
void *data,
- unsigned int len,
- ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data);
+ unsigned int len);
static int hfa384x_isgood_pdrcode(u16 pdrcode);
@@ -820,99 +814,6 @@ static void hfa384x_cb_status(struct hfa384x *hw,
}
}
-static inline int hfa384x_docmd_wait(struct hfa384x *hw,
- struct hfa384x_metacmd *cmd)
-{
- return hfa384x_docmd(hw, DOWAIT, cmd, NULL, NULL, NULL);
-}
-
-static inline int
-hfa384x_docmd_async(struct hfa384x *hw,
- struct hfa384x_metacmd *cmd,
- ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data)
-{
- return hfa384x_docmd(hw, DOASYNC, cmd, cmdcb, usercb, usercb_data);
-}
-
-static inline int
-hfa384x_dorrid_wait(struct hfa384x *hw, u16 rid, void *riddata,
- unsigned int riddatalen)
-{
- return hfa384x_dorrid(hw, DOWAIT,
- rid, riddata, riddatalen, NULL, NULL, NULL);
-}
-
-static inline int
-hfa384x_dorrid_async(struct hfa384x *hw,
- u16 rid, void *riddata, unsigned int riddatalen,
- ctlx_cmdcb_t cmdcb,
- ctlx_usercb_t usercb, void *usercb_data)
-{
- return hfa384x_dorrid(hw, DOASYNC,
- rid, riddata, riddatalen,
- cmdcb, usercb, usercb_data);
-}
-
-static inline int
-hfa384x_dowrid_wait(struct hfa384x *hw, u16 rid, void *riddata,
- unsigned int riddatalen)
-{
- return hfa384x_dowrid(hw, DOWAIT,
- rid, riddata, riddatalen, NULL, NULL, NULL);
-}
-
-static inline int
-hfa384x_dowrid_async(struct hfa384x *hw,
- u16 rid, void *riddata, unsigned int riddatalen,
- ctlx_cmdcb_t cmdcb,
- ctlx_usercb_t usercb, void *usercb_data)
-{
- return hfa384x_dowrid(hw, DOASYNC,
- rid, riddata, riddatalen,
- cmdcb, usercb, usercb_data);
-}
-
-static inline int
-hfa384x_dormem_wait(struct hfa384x *hw,
- u16 page, u16 offset, void *data, unsigned int len)
-{
- return hfa384x_dormem(hw, DOWAIT,
- page, offset, data, len, NULL, NULL, NULL);
-}
-
-static inline int
-hfa384x_dormem_async(struct hfa384x *hw,
- u16 page, u16 offset, void *data, unsigned int len,
- ctlx_cmdcb_t cmdcb,
- ctlx_usercb_t usercb, void *usercb_data)
-{
- return hfa384x_dormem(hw, DOASYNC,
- page, offset, data, len,
- cmdcb, usercb, usercb_data);
-}
-
-static inline int
-hfa384x_dowmem_wait(struct hfa384x *hw,
- u16 page, u16 offset, void *data, unsigned int len)
-{
- return hfa384x_dowmem(hw, DOWAIT,
- page, offset, data, len, NULL, NULL, NULL);
-}
-
-static inline int
-hfa384x_dowmem_async(struct hfa384x *hw,
- u16 page,
- u16 offset,
- void *data,
- unsigned int len,
- ctlx_cmdcb_t cmdcb,
- ctlx_usercb_t usercb, void *usercb_data)
-{
- return hfa384x_dowmem(hw, DOASYNC,
- page, offset, data, len,
- cmdcb, usercb, usercb_data);
-}
-
/*----------------------------------------------------------------
* hfa384x_cmd_initialize
*
@@ -944,7 +845,7 @@ int hfa384x_cmd_initialize(struct hfa384x *hw)
cmd.parm1 = 0;
cmd.parm2 = 0;
- result = hfa384x_docmd_wait(hw, &cmd);
+ result = hfa384x_docmd(hw, &cmd);
pr_debug("cmdresp.init: status=0x%04x, resp0=0x%04x, resp1=0x%04x, resp2=0x%04x\n",
cmd.result.status,
@@ -990,7 +891,7 @@ int hfa384x_cmd_disable(struct hfa384x *hw, u16 macport)
cmd.parm1 = 0;
cmd.parm2 = 0;
- return hfa384x_docmd_wait(hw, &cmd);
+ return hfa384x_docmd(hw, &cmd);
}
/*----------------------------------------------------------------
@@ -1024,7 +925,7 @@ int hfa384x_cmd_enable(struct hfa384x *hw, u16 macport)
cmd.parm1 = 0;
cmd.parm2 = 0;
- return hfa384x_docmd_wait(hw, &cmd);
+ return hfa384x_docmd(hw, &cmd);
}
/*----------------------------------------------------------------
@@ -1067,7 +968,7 @@ int hfa384x_cmd_monitor(struct hfa384x *hw, u16 enable)
cmd.parm1 = 0;
cmd.parm2 = 0;
- return hfa384x_docmd_wait(hw, &cmd);
+ return hfa384x_docmd(hw, &cmd);
}
/*----------------------------------------------------------------
@@ -1124,7 +1025,7 @@ int hfa384x_cmd_download(struct hfa384x *hw, u16 mode, u16 lowaddr,
cmd.parm1 = highaddr;
cmd.parm2 = codelen;
- return hfa384x_docmd_wait(hw, &cmd);
+ return hfa384x_docmd(hw, &cmd);
}
/*----------------------------------------------------------------
@@ -1284,13 +1185,8 @@ cleanup:
*
* Arguments:
* hw device structure
- * mode DOWAIT or DOASYNC
* cmd cmd structure. Includes all arguments and result
* data points. All in host order. in host order
- * cmdcb command-specific callback
- * usercb user callback for async calls, NULL for DOWAIT calls
- * usercb_data user supplied data pointer for async calls, NULL
- * for DOWAIT calls
*
* Returns:
* 0 success
@@ -1306,11 +1202,9 @@ cleanup:
* process
*----------------------------------------------------------------
*/
-static int
+static inline int
hfa384x_docmd(struct hfa384x *hw,
- enum cmd_mode mode,
- struct hfa384x_metacmd *cmd,
- ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data)
+ struct hfa384x_metacmd *cmd)
{
int result;
struct hfa384x_usbctlx *ctlx;
@@ -1333,15 +1227,15 @@ hfa384x_docmd(struct hfa384x *hw,
pr_debug("cmdreq: cmd=0x%04x parm0=0x%04x parm1=0x%04x parm2=0x%04x\n",
cmd->cmd, cmd->parm0, cmd->parm1, cmd->parm2);
- ctlx->reapable = mode;
- ctlx->cmdcb = cmdcb;
- ctlx->usercb = usercb;
- ctlx->usercb_data = usercb_data;
+ ctlx->reapable = DOWAIT;
+ ctlx->cmdcb = NULL;
+ ctlx->usercb = NULL;
+ ctlx->usercb_data = NULL;
result = hfa384x_usbctlx_submit(hw, ctlx);
if (result != 0) {
kfree(ctlx);
- } else if (mode == DOWAIT) {
+ } else {
struct usbctlx_cmd_completor cmd_completor;
struct usbctlx_completor *completor;
@@ -1540,14 +1434,10 @@ done:
*
* Arguments:
* hw device structure
- * mode DOWAIT or DOASYNC
* page MAC address space page (CMD format)
* offset MAC address space offset
* data Ptr to data buffer to receive read
* len Length of the data to read (max == 2048)
- * cmdcb command callback for async calls, NULL for DOWAIT calls
- * usercb user callback for async calls, NULL for DOWAIT calls
- * usercb_data user supplied data pointer for async calls
*
* Returns:
* 0 success
@@ -1559,18 +1449,15 @@ done:
* Side effects:
*
* Call context:
- * interrupt (DOASYNC)
- * process (DOWAIT or DOASYNC)
+ * process (DOWAIT)
*----------------------------------------------------------------
*/
static int
hfa384x_dormem(struct hfa384x *hw,
- enum cmd_mode mode,
u16 page,
u16 offset,
void *data,
- unsigned int len,
- ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data)
+ unsigned int len)
{
int result;
struct hfa384x_usbctlx *ctlx;
@@ -1598,15 +1485,15 @@ hfa384x_dormem(struct hfa384x *hw,
pr_debug("pktsize=%zd\n", ROUNDUP64(sizeof(ctlx->outbuf.rmemreq)));
- ctlx->reapable = mode;
- ctlx->cmdcb = cmdcb;
- ctlx->usercb = usercb;
- ctlx->usercb_data = usercb_data;
+ ctlx->reapable = DOWAIT;
+ ctlx->cmdcb = NULL;
+ ctlx->usercb = NULL;
+ ctlx->usercb_data = NULL;
result = hfa384x_usbctlx_submit(hw, ctlx);
if (result != 0) {
kfree(ctlx);
- } else if (mode == DOWAIT) {
+ } else {
struct usbctlx_rmem_completor completor;
result =
@@ -1632,14 +1519,10 @@ done:
*
* Arguments:
* hw device structure
- * mode DOWAIT or DOASYNC
* page MAC address space page (CMD format)
* offset MAC address space offset
* data Ptr to data buffer containing write data
* len Length of the data to read (max == 2048)
- * cmdcb command callback for async calls, NULL for DOWAIT calls
- * usercb user callback for async calls, NULL for DOWAIT calls
- * usercb_data user supplied data pointer for async calls.
*
* Returns:
* 0 success
@@ -1652,17 +1535,15 @@ done:
*
* Call context:
* interrupt (DOWAIT)
- * process (DOWAIT or DOASYNC)
+ * process (DOWAIT)
*----------------------------------------------------------------
*/
static int
hfa384x_dowmem(struct hfa384x *hw,
- enum cmd_mode mode,
u16 page,
u16 offset,
void *data,
- unsigned int len,
- ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data)
+ unsigned int len)
{
int result;
struct hfa384x_usbctlx *ctlx;
@@ -1689,15 +1570,15 @@ hfa384x_dowmem(struct hfa384x *hw,
sizeof(ctlx->outbuf.wmemreq.offset) +
sizeof(ctlx->outbuf.wmemreq.page) + len;
- ctlx->reapable = mode;
- ctlx->cmdcb = cmdcb;
- ctlx->usercb = usercb;
- ctlx->usercb_data = usercb_data;
+ ctlx->reapable = DOWAIT;
+ ctlx->cmdcb = NULL;
+ ctlx->usercb = NULL;
+ ctlx->usercb_data = NULL;
result = hfa384x_usbctlx_submit(hw, ctlx);
if (result != 0) {
kfree(ctlx);
- } else if (mode == DOWAIT) {
+ } else {
struct usbctlx_cmd_completor completor;
struct hfa384x_cmdresult wmemresult;
@@ -2004,10 +1885,10 @@ int hfa384x_drvr_flashdl_write(struct hfa384x *hw, u32 daddr,
writelen = writelen > HFA384x_USB_RWMEM_MAXLEN ?
HFA384x_USB_RWMEM_MAXLEN : writelen;
- result = hfa384x_dowmem_wait(hw,
- writepage,
- writeoffset,
- writebuf, writelen);
+ result = hfa384x_dowmem(hw,
+ writepage,
+ writeoffset,
+ writebuf, writelen);
}
/* set the download 'write flash' mode */
@@ -2061,7 +1942,7 @@ exit_proc:
*/
int hfa384x_drvr_getconfig(struct hfa384x *hw, u16 rid, void *buf, u16 len)
{
- return hfa384x_dorrid_wait(hw, rid, buf, len);
+ return hfa384x_dorrid(hw, DOWAIT, rid, buf, len, NULL, NULL, NULL);
}
/*----------------------------------------------------------------
@@ -2094,8 +1975,8 @@ hfa384x_drvr_setconfig_async(struct hfa384x *hw,
void *buf,
u16 len, ctlx_usercb_t usercb, void *usercb_data)
{
- return hfa384x_dowrid_async(hw, rid, buf, len,
- hfa384x_cb_status, usercb, usercb_data);
+ return hfa384x_dowrid(hw, DOASYNC, rid, buf, len, hfa384x_cb_status,
+ usercb, usercb_data);
}
/*----------------------------------------------------------------
@@ -2261,12 +2142,11 @@ int hfa384x_drvr_ramdl_write(struct hfa384x *hw, u32 daddr, void *buf, u32 len)
currlen = HFA384x_USB_RWMEM_MAXLEN;
/* Do blocking ctlx */
- result = hfa384x_dowmem_wait(hw,
- currpage,
- curroffset,
- data +
- (i * HFA384x_USB_RWMEM_MAXLEN),
- currlen);
+ result = hfa384x_dowmem(hw,
+ currpage,
+ curroffset,
+ data + (i * HFA384x_USB_RWMEM_MAXLEN),
+ currlen);
if (result)
break;
@@ -2338,8 +2218,8 @@ int hfa384x_drvr_readpda(struct hfa384x *hw, void *buf, unsigned int len)
curroffset = HFA384x_ADDR_CMD_MKOFF(pdaloc[i].cardaddr);
/* units of bytes */
- result = hfa384x_dormem_wait(hw, currpage, curroffset, buf,
- len);
+ result = hfa384x_dormem(hw, currpage, curroffset, buf,
+ len);
if (result) {
netdev_warn(hw->wlandev->netdev,
@@ -2422,7 +2302,7 @@ int hfa384x_drvr_readpda(struct hfa384x *hw, void *buf, unsigned int len)
*/
int hfa384x_drvr_setconfig(struct hfa384x *hw, u16 rid, void *buf, u16 len)
{
- return hfa384x_dowrid_wait(hw, rid, buf, len);
+ return hfa384x_dowrid(hw, DOWAIT, rid, buf, len, NULL, NULL, NULL);
}
/*----------------------------------------------------------------
diff --git a/drivers/staging/wlan-ng/prism2mib.c b/drivers/staging/wlan-ng/prism2mib.c
index 1eba5fa28d8f..7d7d77b04255 100644
--- a/drivers/staging/wlan-ng/prism2mib.c
+++ b/drivers/staging/wlan-ng/prism2mib.c
@@ -126,13 +126,6 @@ static int prism2mib_privacyinvoked(struct mibrec *mib,
struct p80211msg_dot11req_mibset *msg,
void *data);
-static int prism2mib_excludeunencrypted(struct mibrec *mib,
- int isget,
- struct wlandevice *wlandev,
- struct hfa384x *hw,
- struct p80211msg_dot11req_mibset *msg,
- void *data);
-
static int
prism2mib_fragmentationthreshold(struct mibrec *mib,
int isget,
@@ -176,7 +169,7 @@ static struct mibrec mibtab[] = {
{DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
F_STA | F_READ | F_WRITE,
HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_EXCLUDE, 0,
- prism2mib_excludeunencrypted},
+ prism2mib_flag},
/* dot11mac MIB's */
@@ -594,41 +587,6 @@ static int prism2mib_privacyinvoked(struct mibrec *mib,
}
/*
- * prism2mib_excludeunencrypted
- *
- * Get/set the dot11ExcludeUnencrypted value.
- *
- * MIB record parameters:
- * parm1 Prism2 RID value.
- * parm2 Bit value for ExcludeUnencrypted flag.
- * parm3 Not used.
- *
- * Arguments:
- * mib MIB record.
- * isget MIBGET/MIBSET flag.
- * wlandev wlan device structure.
- * priv "priv" structure.
- * hw "hw" structure.
- * msg Message structure.
- * data Data buffer.
- *
- * Returns:
- * 0 - Success.
- * ~0 - Error.
- *
- */
-
-static int prism2mib_excludeunencrypted(struct mibrec *mib,
- int isget,
- struct wlandevice *wlandev,
- struct hfa384x *hw,
- struct p80211msg_dot11req_mibset *msg,
- void *data)
-{
- return prism2mib_flag(mib, isget, wlandev, hw, msg, data);
-}
-
-/*
* prism2mib_fragmentationthreshold
*
* Get/set the fragmentation threshold.
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index fb5441399131..8f25496188aa 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -846,7 +846,7 @@ static int prism2sta_getcardinfo(struct wlandevice *wlandev)
result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER,
snum, HFA384x_RID_NICSERIALNUMBER_LEN);
if (!result) {
- netdev_info(wlandev->netdev, "Prism2 card SN: %*pEhp\n",
+ netdev_info(wlandev->netdev, "Prism2 card SN: %*pE\n",
HFA384x_RID_NICSERIALNUMBER_LEN, snum);
} else {
netdev_err(wlandev->netdev, "Failed to retrieve Prism2 Card SN\n");
diff --git a/drivers/staging/wusbcore/Documentation/wusb-cbaf b/drivers/staging/wusbcore/Documentation/wusb-cbaf
new file mode 100644
index 000000000000..8b3d43efce90
--- /dev/null
+++ b/drivers/staging/wusbcore/Documentation/wusb-cbaf
@@ -0,0 +1,130 @@
+#! /bin/bash
+#
+
+set -e
+
+progname=$(basename $0)
+function help
+{
+ cat <<EOF
+Usage: $progname COMMAND DEVICEs [ARGS]
+
+Command for manipulating the pairing/authentication credentials of a
+Wireless USB device that supports wired-mode Cable-Based-Association.
+
+Works in conjunction with the wusb-cba.ko driver from http://linuxuwb.org.
+
+
+DEVICE
+
+ sysfs path to the device to authenticate; for example, both this
+ guys are the same:
+
+ /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.4/1-4.4:1.1
+ /sys/bus/usb/drivers/wusb-cbaf/1-4.4:1.1
+
+COMMAND/ARGS are
+
+ start
+
+ Start a WUSB host controller (by setting up a CHID)
+
+ set-chid DEVICE HOST-CHID HOST-BANDGROUP HOST-NAME
+
+ Sets host information in the device; after this you can call the
+ get-cdid to see how does this device report itself to us.
+
+ get-cdid DEVICE
+
+ Get the device ID associated to the HOST-CHID we sent with
+ 'set-chid'. We might not know about it.
+
+ set-cc DEVICE
+
+ If we allow the device to connect, set a random new CDID and CK
+ (connection key). Device saves them for the next time it wants to
+ connect wireless. We save them for that next time also so we can
+ authenticate the device (when we see the CDID he uses to id
+ itself) and the CK to crypto talk to it.
+
+CHID is always 16 hex bytes in 'XX YY ZZ...' form
+BANDGROUP is almost always 0001
+
+Examples:
+
+ You can default most arguments to '' to get a sane value:
+
+ $ $progname set-chid '' '' '' "My host name"
+
+ A full sequence:
+
+ $ $progname set-chid '' '' '' "My host name"
+ $ $progname get-cdid ''
+ $ $progname set-cc ''
+
+EOF
+}
+
+
+# Defaults
+# FIXME: CHID should come from a database :), band group from the host
+host_CHID="00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff"
+host_band_group="0001"
+host_name=$(hostname)
+
+devs="$(echo /sys/bus/usb/drivers/wusb-cbaf/[0-9]*)"
+hdevs="$(for h in /sys/class/uwb_rc/*/wusbhc; do readlink -f $h; done)"
+
+result=0
+case $1 in
+ start)
+ for dev in ${2:-$hdevs}
+ do
+ echo $host_CHID > $dev/wusb_chid
+ echo I: started host $(basename $dev) >&2
+ done
+ ;;
+ stop)
+ for dev in ${2:-$hdevs}
+ do
+ echo 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 > $dev/wusb_chid
+ echo I: stopped host $(basename $dev) >&2
+ done
+ ;;
+ set-chid)
+ shift
+ for dev in ${2:-$devs}; do
+ echo "${4:-$host_name}" > $dev/wusb_host_name
+ echo "${3:-$host_band_group}" > $dev/wusb_host_band_groups
+ echo ${2:-$host_CHID} > $dev/wusb_chid
+ done
+ ;;
+ get-cdid)
+ for dev in ${2:-$devs}
+ do
+ cat $dev/wusb_cdid
+ done
+ ;;
+ set-cc)
+ for dev in ${2:-$devs}; do
+ shift
+ CDID="$(head --bytes=16 /dev/urandom | od -tx1 -An)"
+ CK="$(head --bytes=16 /dev/urandom | od -tx1 -An)"
+ echo "$CDID" > $dev/wusb_cdid
+ echo "$CK" > $dev/wusb_ck
+
+ echo I: CC set >&2
+ echo "CHID: $(cat $dev/wusb_chid)"
+ echo "CDID:$CDID"
+ echo "CK: $CK"
+ done
+ ;;
+ help|h|--help|-h)
+ help
+ ;;
+ *)
+ echo "E: Unknown usage" 1>&2
+ help 1>&2
+ result=1
+esac
+exit $result
diff --git a/drivers/staging/wusbcore/Documentation/wusb-design-overview.rst b/drivers/staging/wusbcore/Documentation/wusb-design-overview.rst
new file mode 100644
index 000000000000..dc5e21609bb5
--- /dev/null
+++ b/drivers/staging/wusbcore/Documentation/wusb-design-overview.rst
@@ -0,0 +1,457 @@
+================================
+Linux UWB + Wireless USB + WiNET
+================================
+
+ Copyright (C) 2005-2006 Intel Corporation
+
+ Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License version
+ 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+
+Please visit http://bughost.org/thewiki/Design-overview.txt-1.8 for
+updated content.
+
+ * Design-overview.txt-1.8
+
+This code implements a Ultra Wide Band stack for Linux, as well as
+drivers for the USB based UWB radio controllers defined in the
+Wireless USB 1.0 specification (including Wireless USB host controller
+and an Intel WiNET controller).
+
+.. Contents
+ 1. Introduction
+ 1. HWA: Host Wire adapters, your Wireless USB dongle
+
+ 2. DWA: Device Wired Adaptor, a Wireless USB hub for wired
+ devices
+ 3. WHCI: Wireless Host Controller Interface, the PCI WUSB host
+ adapter
+ 2. The UWB stack
+ 1. Devices and hosts: the basic structure
+
+ 2. Host Controller life cycle
+
+ 3. On the air: beacons and enumerating the radio neighborhood
+
+ 4. Device lists
+ 5. Bandwidth allocation
+
+ 3. Wireless USB Host Controller drivers
+
+ 4. Glossary
+
+
+Introduction
+============
+
+UWB is a wide-band communication protocol that is to serve also as the
+low-level protocol for others (much like TCP sits on IP). Currently
+these others are Wireless USB and TCP/IP, but seems Bluetooth and
+Firewire/1394 are coming along.
+
+UWB uses a band from roughly 3 to 10 GHz, transmitting at a max of
+~-41dB (or 0.074 uW/MHz--geography specific data is still being
+negotiated w/ regulators, so watch for changes). That band is divided in
+a bunch of ~1.5 GHz wide channels (or band groups) composed of three
+subbands/subchannels (528 MHz each). Each channel is independent of each
+other, so you could consider them different "busses". Initially this
+driver considers them all a single one.
+
+Radio time is divided in 65536 us long /superframes/, each one divided
+in 256 256us long /MASs/ (Media Allocation Slots), which are the basic
+time/media allocation units for transferring data. At the beginning of
+each superframe there is a Beacon Period (BP), where every device
+transmit its beacon on a single MAS. The length of the BP depends on how
+many devices are present and the length of their beacons.
+
+Devices have a MAC (fixed, 48 bit address) and a device (changeable, 16
+bit address) and send periodic beacons to advertise themselves and pass
+info on what they are and do. They advertise their capabilities and a
+bunch of other stuff.
+
+The different logical parts of this driver are:
+
+ *
+
+ *UWB*: the Ultra-Wide-Band stack -- manages the radio and
+ associated spectrum to allow for devices sharing it. Allows to
+ control bandwidth assignment, beaconing, scanning, etc
+
+ *
+
+ *WUSB*: the layer that sits on top of UWB to provide Wireless USB.
+ The Wireless USB spec defines means to control a UWB radio and to
+ do the actual WUSB.
+
+
+HWA: Host Wire adapters, your Wireless USB dongle
+-------------------------------------------------
+
+WUSB also defines a device called a Host Wire Adaptor (HWA), which in
+mere terms is a USB dongle that enables your PC to have UWB and Wireless
+USB. The Wireless USB Host Controller in a HWA looks to the host like a
+[Wireless] USB controller connected via USB (!)
+
+The HWA itself is broken in two or three main interfaces:
+
+ *
+
+ *RC*: Radio control -- this implements an interface to the
+ Ultra-Wide-Band radio controller. The driver for this implements a
+ USB-based UWB Radio Controller to the UWB stack.
+
+ *
+
+ *HC*: the wireless USB host controller. It looks like a USB host
+ whose root port is the radio and the WUSB devices connect to it.
+ To the system it looks like a separate USB host. The driver (will)
+ implement a USB host controller (similar to UHCI, OHCI or EHCI)
+ for which the root hub is the radio...To reiterate: it is a USB
+ controller that is connected via USB instead of PCI.
+
+ *
+
+ *WINET*: some HW provide a WiNET interface (IP over UWB). This
+ package provides a driver for it (it looks like a network
+ interface, winetX). The driver detects when there is a link up for
+ their type and kick into gear.
+
+
+DWA: Device Wired Adaptor, a Wireless USB hub for wired devices
+---------------------------------------------------------------
+
+These are the complement to HWAs. They are a USB host for connecting
+wired devices, but it is connected to your PC connected via Wireless
+USB. To the system it looks like yet another USB host. To the untrained
+eye, it looks like a hub that connects upstream wirelessly.
+
+We still offer no support for this; however, it should share a lot of
+code with the HWA-RC driver; there is a bunch of factorization work that
+has been done to support that in upcoming releases.
+
+
+WHCI: Wireless Host Controller Interface, the PCI WUSB host adapter
+-------------------------------------------------------------------
+
+This is your usual PCI device that implements WHCI. Similar in concept
+to EHCI, it allows your wireless USB devices (including DWAs) to connect
+to your host via a PCI interface. As in the case of the HWA, it has a
+Radio Control interface and the WUSB Host Controller interface per se.
+
+There is still no driver support for this, but will be in upcoming
+releases.
+
+
+The UWB stack
+=============
+
+The main mission of the UWB stack is to keep a tally of which devices
+are in radio proximity to allow drivers to connect to them. As well, it
+provides an API for controlling the local radio controllers (RCs from
+now on), such as to start/stop beaconing, scan, allocate bandwidth, etc.
+
+
+Devices and hosts: the basic structure
+--------------------------------------
+
+The main building block here is the UWB device (struct uwb_dev). For
+each device that pops up in radio presence (ie: the UWB host receives a
+beacon from it) you get a struct uwb_dev that will show up in
+/sys/bus/uwb/devices.
+
+For each RC that is detected, a new struct uwb_rc and struct uwb_dev are
+created. An entry is also created in /sys/class/uwb_rc for each RC.
+
+Each RC driver is implemented by a separate driver that plugs into the
+interface that the UWB stack provides through a struct uwb_rc_ops. The
+spec creators have been nice enough to make the message format the same
+for HWA and WHCI RCs, so the driver is really a very thin transport that
+moves the requests from the UWB API to the device [/uwb_rc_ops->cmd()/]
+and sends the replies and notifications back to the API
+[/uwb_rc_neh_grok()/]. Notifications are handled to the UWB daemon, that
+is chartered, among other things, to keep the tab of how the UWB radio
+neighborhood looks, creating and destroying devices as they show up or
+disappear.
+
+Command execution is very simple: a command block is sent and a event
+block or reply is expected back. For sending/receiving command/events, a
+handle called /neh/ (Notification/Event Handle) is opened with
+/uwb_rc_neh_open()/.
+
+The HWA-RC (USB dongle) driver (drivers/uwb/hwa-rc.c) does this job for
+the USB connected HWA. Eventually, drivers/whci-rc.c will do the same
+for the PCI connected WHCI controller.
+
+
+Host Controller life cycle
+--------------------------
+
+So let's say we connect a dongle to the system: it is detected and
+firmware uploaded if needed [for Intel's i1480
+/drivers/uwb/ptc/usb.c:ptc_usb_probe()/] and then it is reenumerated.
+Now we have a real HWA device connected and
+/drivers/uwb/hwa-rc.c:hwarc_probe()/ picks it up, that will set up the
+Wire-Adaptor environment and then suck it into the UWB stack's vision of
+the world [/drivers/uwb/lc-rc.c:uwb_rc_add()/].
+
+ *
+
+ [*] The stack should put a new RC to scan for devices
+ [/uwb_rc_scan()/] so it finds what's available around and tries to
+ connect to them, but this is policy stuff and should be driven
+ from user space. As of now, the operator is expected to do it
+ manually; see the release notes for documentation on the procedure.
+
+When a dongle is disconnected, /drivers/uwb/hwa-rc.c:hwarc_disconnect()/
+takes time of tearing everything down safely (or not...).
+
+
+On the air: beacons and enumerating the radio neighborhood
+----------------------------------------------------------
+
+So assuming we have devices and we have agreed for a channel to connect
+on (let's say 9), we put the new RC to beacon:
+
+ *
+
+ $ echo 9 0 > /sys/class/uwb_rc/uwb0/beacon
+
+Now it is visible. If there were other devices in the same radio channel
+and beacon group (that's what the zero is for), the dongle's radio
+control interface will send beacon notifications on its
+notification/event endpoint (NEEP). The beacon notifications are part of
+the event stream that is funneled into the API with
+/drivers/uwb/neh.c:uwb_rc_neh_grok()/ and delivered to the UWBD, the UWB
+daemon through a notification list.
+
+UWBD wakes up and scans the event list; finds a beacon and adds it to
+the BEACON CACHE (/uwb_beca/). If he receives a number of beacons from
+the same device, he considers it to be 'onair' and creates a new device
+[/drivers/uwb/lc-dev.c:uwbd_dev_onair()/]. Similarly, when no beacons
+are received in some time, the device is considered gone and wiped out
+[uwbd calls periodically /uwb/beacon.c:uwb_beca_purge()/ that will purge
+the beacon cache of dead devices].
+
+
+Device lists
+------------
+
+All UWB devices are kept in the list of the struct bus_type uwb_bus_type.
+
+
+Bandwidth allocation
+--------------------
+
+The UWB stack maintains a local copy of DRP availability through
+processing of incoming *DRP Availability Change* notifications. This
+local copy is currently used to present the current bandwidth
+availability to the user through the sysfs file
+/sys/class/uwb_rc/uwbx/bw_avail. In the future the bandwidth
+availability information will be used by the bandwidth reservation
+routines.
+
+The bandwidth reservation routines are in progress and are thus not
+present in the current release. When completed they will enable a user
+to initiate DRP reservation requests through interaction with sysfs. DRP
+reservation requests from remote UWB devices will also be handled. The
+bandwidth management done by the UWB stack will include callbacks to the
+higher layers will enable the higher layers to use the reservations upon
+completion. [Note: The bandwidth reservation work is in progress and
+subject to change.]
+
+
+Wireless USB Host Controller drivers
+====================================
+
+*WARNING* This section needs a lot of work!
+
+As explained above, there are three different types of HCs in the WUSB
+world: HWA-HC, DWA-HC and WHCI-HC.
+
+HWA-HC and DWA-HC share that they are Wire-Adapters (USB or WUSB
+connected controllers), and their transfer management system is almost
+identical. So is their notification delivery system.
+
+HWA-HC and WHCI-HC share that they are both WUSB host controllers, so
+they have to deal with WUSB device life cycle and maintenance, wireless
+root-hub
+
+HWA exposes a Host Controller interface (HWA-HC 0xe0/02/02). This has
+three endpoints (Notifications, Data Transfer In and Data Transfer
+Out--known as NEP, DTI and DTO in the code).
+
+We reserve UWB bandwidth for our Wireless USB Cluster, create a Cluster
+ID and tell the HC to use all that. Then we start it. This means the HC
+starts sending MMCs.
+
+ *
+
+ The MMCs are blocks of data defined somewhere in the WUSB1.0 spec
+ that define a stream in the UWB channel time allocated for sending
+ WUSB IEs (host to device commands/notifications) and Device
+ Notifications (device initiated to host). Each host defines a
+ unique Wireless USB cluster through MMCs. Devices can connect to a
+ single cluster at the time. The IEs are Information Elements, and
+ among them are the bandwidth allocations that tell each device
+ when can they transmit or receive.
+
+Now it all depends on external stimuli.
+
+New device connection
+---------------------
+
+A new device pops up, it scans the radio looking for MMCs that give out
+the existence of Wireless USB channels. Once one (or more) are found,
+selects which one to connect to. Sends a /DN_Connect/ (device
+notification connect) during the DNTS (Device Notification Time
+Slot--announced in the MMCs
+
+HC picks the /DN_Connect/ out (nep module sends to notif.c for delivery
+into /devconnect/). This process starts the authentication process for
+the device. First we allocate a /fake port/ and assign an
+unauthenticated address (128 to 255--what we really do is
+0x80 | fake_port_idx). We fiddle with the fake port status and /hub_wq/
+sees a new connection, so he moves on to enable the fake port with a reset.
+
+So now we are in the reset path -- we know we have a non-yet enumerated
+device with an unauthorized address; we ask user space to authenticate
+(FIXME: not yet done, similar to bluetooth pairing), then we do the key
+exchange (FIXME: not yet done) and issue a /set address 0/ to bring the
+device to the default state. Device is authenticated.
+
+From here, the USB stack takes control through the usb_hcd ops. hub_wq
+has seen the port status changes, as we have been toggling them. It will
+start enumerating and doing transfers through usb_hcd->urb_enqueue() to
+read descriptors and move our data.
+
+Device life cycle and keep alives
+---------------------------------
+
+Every time there is a successful transfer to/from a device, we update a
+per-device activity timestamp. If not, every now and then we check and
+if the activity timestamp gets old, we ping the device by sending it a
+Keep Alive IE; it responds with a /DN_Alive/ pong during the DNTS (this
+arrives to us as a notification through
+devconnect.c:wusb_handle_dn_alive(). If a device times out, we
+disconnect it from the system (cleaning up internal information and
+toggling the bits in the fake hub port, which kicks hub_wq into removing
+the rest of the stuff).
+
+This is done through devconnect:__wusb_check_devs(), which will scan the
+device list looking for whom needs refreshing.
+
+If the device wants to disconnect, it will either die (ugly) or send a
+/DN_Disconnect/ that will prompt a disconnection from the system.
+
+Sending and receiving data
+--------------------------
+
+Data is sent and received through /Remote Pipes/ (rpipes). An rpipe is
+/aimed/ at an endpoint in a WUSB device. This is the same for HWAs and
+DWAs.
+
+Each HC has a number of rpipes and buffers that can be assigned to them;
+when doing a data transfer (xfer), first the rpipe has to be aimed and
+prepared (buffers assigned), then we can start queueing requests for
+data in or out.
+
+Data buffers have to be segmented out before sending--so we send first a
+header (segment request) and then if there is any data, a data buffer
+immediately after to the DTI interface (yep, even the request). If our
+buffer is bigger than the max segment size, then we just do multiple
+requests.
+
+[This sucks, because doing USB scatter gatter in Linux is resource
+intensive, if any...not that the current approach is not. It just has to
+be cleaned up a lot :)].
+
+If reading, we don't send data buffers, just the segment headers saying
+we want to read segments.
+
+When the xfer is executed, we receive a notification that says data is
+ready in the DTI endpoint (handled through
+xfer.c:wa_handle_notif_xfer()). In there we read from the DTI endpoint a
+descriptor that gives us the status of the transfer, its identification
+(given when we issued it) and the segment number. If it was a data read,
+we issue another URB to read into the destination buffer the chunk of
+data coming out of the remote endpoint. Done, wait for the next guy. The
+callbacks for the URBs issued from here are the ones that will declare
+the xfer complete at some point and call its callback.
+
+Seems simple, but the implementation is not trivial.
+
+ *
+
+ *WARNING* Old!!
+
+The main xfer descriptor, wa_xfer (equivalent to a URB) contains an
+array of segments, tallys on segments and buffers and callback
+information. Buried in there is a lot of URBs for executing the segments
+and buffer transfers.
+
+For OUT xfers, there is an array of segments, one URB for each, another
+one of buffer URB. When submitting, we submit URBs for segment request
+1, buffer 1, segment 2, buffer 2...etc. Then we wait on the DTI for xfer
+result data; when all the segments are complete, we call the callback to
+finalize the transfer.
+
+For IN xfers, we only issue URBs for the segments we want to read and
+then wait for the xfer result data.
+
+URB mapping into xfers
+^^^^^^^^^^^^^^^^^^^^^^
+
+This is done by hwahc_op_urb_[en|de]queue(). In enqueue() we aim an
+rpipe to the endpoint where we have to transmit, create a transfer
+context (wa_xfer) and submit it. When the xfer is done, our callback is
+called and we assign the status bits and release the xfer resources.
+
+In dequeue() we are basically cancelling/aborting the transfer. We issue
+a xfer abort request to the HC, cancel all the URBs we had submitted
+and not yet done and when all that is done, the xfer callback will be
+called--this will call the URB callback.
+
+
+Glossary
+========
+
+*DWA* -- Device Wire Adapter
+
+USB host, wired for downstream devices, upstream connects wirelessly
+with Wireless USB.
+
+*EVENT* -- Response to a command on the NEEP
+
+*HWA* -- Host Wire Adapter / USB dongle for UWB and Wireless USB
+
+*NEH* -- Notification/Event Handle
+
+Handle/file descriptor for receiving notifications or events. The WA
+code requires you to get one of this to listen for notifications or
+events on the NEEP.
+
+*NEEP* -- Notification/Event EndPoint
+
+Stuff related to the management of the first endpoint of a HWA USB
+dongle that is used to deliver an stream of events and notifications to
+the host.
+
+*NOTIFICATION* -- Message coming in the NEEP as response to something.
+
+*RC* -- Radio Control
+
+Design-overview.txt-1.8 (last edited 2006-11-04 12:22:24 by
+InakyPerezGonzalez)
diff --git a/drivers/staging/wusbcore/Kconfig b/drivers/staging/wusbcore/Kconfig
new file mode 100644
index 000000000000..a559d023b508
--- /dev/null
+++ b/drivers/staging/wusbcore/Kconfig
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Wireless USB Core configuration
+#
+config USB_WUSB
+ tristate "Enable Wireless USB extensions"
+ depends on UWB && USB
+ select CRYPTO
+ select CRYPTO_AES
+ select CRYPTO_CCM
+ help
+ Enable the host-side support for Wireless USB.
+
+ To compile this support select Y (built in). It is safe to
+ select even if you don't have the hardware.
+
+config USB_WUSB_CBAF
+ tristate "Support WUSB Cable Based Association (CBA)"
+ depends on USB
+ help
+ Some WUSB devices support Cable Based Association. It's used to
+ enable the secure communication between the host and the
+ device.
+
+ Enable this option if your WUSB device must to be connected
+ via wired USB before establishing a wireless link.
+
+ It is safe to select even if you don't have a compatible
+ hardware.
+
+config USB_WUSB_CBAF_DEBUG
+ bool "Enable CBA debug messages"
+ depends on USB_WUSB_CBAF
+ help
+ Say Y here if you want the CBA to produce a bunch of debug messages
+ to the system log. Select this if you are having a problem with
+ CBA support and want to see more of what is going on.
+
+source "drivers/staging/wusbcore/host/Kconfig"
diff --git a/drivers/staging/wusbcore/Makefile b/drivers/staging/wusbcore/Makefile
new file mode 100644
index 000000000000..b47b874268ac
--- /dev/null
+++ b/drivers/staging/wusbcore/Makefile
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+ccflags-$(CONFIG_USB_WUSB_CBAF_DEBUG) := -DDEBUG
+
+obj-$(CONFIG_USB_WUSB) += wusbcore.o
+obj-$(CONFIG_USB_HWA_HCD) += wusb-wa.o
+obj-$(CONFIG_USB_WUSB_CBAF) += wusb-cbaf.o
+
+
+wusbcore-y := \
+ crypto.o \
+ devconnect.o \
+ dev-sysfs.o \
+ mmc.o \
+ pal.o \
+ rh.o \
+ reservation.o \
+ security.o \
+ wusbhc.o
+
+wusb-cbaf-y := cbaf.o
+
+wusb-wa-y := \
+ wa-hc.o \
+ wa-nep.o \
+ wa-rpipe.o \
+ wa-xfer.o
+
+obj-y += host/
diff --git a/drivers/staging/wusbcore/TODO b/drivers/staging/wusbcore/TODO
new file mode 100644
index 000000000000..abae57000534
--- /dev/null
+++ b/drivers/staging/wusbcore/TODO
@@ -0,0 +1,8 @@
+TODO: Remove in late 2019 unless there are users
+
+There seems to not be any real wireless USB devices anywhere in the wild
+anymore. It turned out to be a failed technology :(
+
+This will be removed from the tree if no one objects.
+
+Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/staging/wusbcore/cbaf.c b/drivers/staging/wusbcore/cbaf.c
new file mode 100644
index 000000000000..57062eaf7558
--- /dev/null
+++ b/drivers/staging/wusbcore/cbaf.c
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB - Cable Based Association
+ *
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * WUSB devices have to be paired (associated in WUSB lingo) so
+ * that they can connect to the system.
+ *
+ * One way of pairing is using CBA-Cable Based Association. First
+ * time you plug the device with a cable, association is done between
+ * host and device and subsequent times, you can connect wirelessly
+ * without having to associate again. That's the idea.
+ *
+ * This driver does nothing Earth shattering. It just provides an
+ * interface to chat with the wire-connected device so we can get a
+ * CDID (device ID) that might have been previously associated to a
+ * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet
+ * (connection context), with the CK being the secret, or connection
+ * key. This is the pairing data.
+ *
+ * When a device with the CBA capability connects, the probe routine
+ * just creates a bunch of sysfs files that a user space enumeration
+ * manager uses to allow it to connect wirelessly to the system or not.
+ *
+ * The process goes like this:
+ *
+ * 1. Device plugs, cbaf is loaded, notifications happen.
+ *
+ * 2. The connection manager (CM) sees a device with CBAF capability
+ * (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE).
+ *
+ * 3. The CM writes the host name, supported band groups, and the CHID
+ * (host ID) into the wusb_host_name, wusb_host_band_groups and
+ * wusb_chid files. These get sent to the device and the CDID (if
+ * any) for this host is requested.
+ *
+ * 4. The CM can verify that the device's supported band groups
+ * (wusb_device_band_groups) are compatible with the host.
+ *
+ * 5. The CM reads the wusb_cdid file.
+ *
+ * 6. The CM looks up its database
+ *
+ * 6.1 If it has a matching CHID,CDID entry, the device has been
+ * authorized before (paired) and nothing further needs to be
+ * done.
+ *
+ * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in
+ * its database), the device is assumed to be not known. The CM
+ * may associate the host with device by: writing a randomly
+ * generated CDID to wusb_cdid and then a random CK to wusb_ck
+ * (this uploads the new CC to the device).
+ *
+ * CMD may choose to prompt the user before associating with a new
+ * device.
+ *
+ * 7. Device is unplugged.
+ *
+ * When the device tries to connect wirelessly, it will present its
+ * CDID to the WUSB host controller. The CM will query the
+ * database. If the CHID/CDID pair found, it will (with a 4-way
+ * handshake) challenge the device to demonstrate it has the CK secret
+ * key (from our database) without actually exchanging it. Once
+ * satisfied, crypto keys are derived from the CK, the device is
+ * connected and all communication is encrypted.
+ *
+ * References:
+ * [WUSB-AM] Association Models Supplement to the Certified Wireless
+ * Universal Serial Bus Specification, version 1.0.
+ */
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/usb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include "../uwb/uwb.h"
+#include "include/wusb.h"
+#include "include/association.h"
+
+#define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */
+
+/* An instance of a Cable-Based-Association-Framework device */
+struct cbaf {
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+ void *buffer;
+ size_t buffer_size;
+
+ struct wusb_ckhdid chid;
+ char host_name[CBA_NAME_LEN];
+ u16 host_band_groups;
+
+ struct wusb_ckhdid cdid;
+ char device_name[CBA_NAME_LEN];
+ u16 device_band_groups;
+
+ struct wusb_ckhdid ck;
+};
+
+/*
+ * Verify that a CBAF USB-interface has what we need
+ *
+ * According to [WUSB-AM], CBA devices should provide at least two
+ * interfaces:
+ * - RETRIEVE_HOST_INFO
+ * - ASSOCIATE
+ *
+ * If the device doesn't provide these interfaces, we do not know how
+ * to deal with it.
+ */
+static int cbaf_check(struct cbaf *cbaf)
+{
+ int result;
+ struct device *dev = &cbaf->usb_iface->dev;
+ struct wusb_cbaf_assoc_info *assoc_info;
+ struct wusb_cbaf_assoc_request *assoc_request;
+ size_t assoc_size;
+ void *itr, *top;
+ int ar_rhi = 0, ar_assoc = 0;
+
+ result = usb_control_msg(
+ cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
+ CBAF_REQ_GET_ASSOCIATION_INFORMATION,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ cbaf->buffer, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "Cannot get available association types: %d\n",
+ result);
+ return result;
+ }
+
+ assoc_info = cbaf->buffer;
+ if (result < sizeof(*assoc_info)) {
+ dev_err(dev, "Not enough data to decode association info "
+ "header (%zu vs %zu bytes required)\n",
+ (size_t)result, sizeof(*assoc_info));
+ return result;
+ }
+
+ assoc_size = le16_to_cpu(assoc_info->Length);
+ if (result < assoc_size) {
+ dev_err(dev, "Not enough data to decode association info "
+ "(%zu vs %zu bytes required)\n",
+ (size_t)assoc_size, sizeof(*assoc_info));
+ return result;
+ }
+ /*
+ * From now on, we just verify, but won't error out unless we
+ * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE}
+ * types.
+ */
+ itr = cbaf->buffer + sizeof(*assoc_info);
+ top = cbaf->buffer + assoc_size;
+ dev_dbg(dev, "Found %u association requests (%zu bytes)\n",
+ assoc_info->NumAssociationRequests, assoc_size);
+
+ while (itr < top) {
+ u16 ar_type, ar_subtype;
+ u32 ar_size;
+ const char *ar_name;
+
+ assoc_request = itr;
+
+ if (top - itr < sizeof(*assoc_request)) {
+ dev_err(dev, "Not enough data to decode association "
+ "request (%zu vs %zu bytes needed)\n",
+ top - itr, sizeof(*assoc_request));
+ break;
+ }
+
+ ar_type = le16_to_cpu(assoc_request->AssociationTypeId);
+ ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId);
+ ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize);
+ ar_name = "unknown";
+
+ switch (ar_type) {
+ case AR_TYPE_WUSB:
+ /* Verify we have what is mandated by [WUSB-AM]. */
+ switch (ar_subtype) {
+ case AR_TYPE_WUSB_RETRIEVE_HOST_INFO:
+ ar_name = "RETRIEVE_HOST_INFO";
+ ar_rhi = 1;
+ break;
+ case AR_TYPE_WUSB_ASSOCIATE:
+ /* send assoc data */
+ ar_name = "ASSOCIATE";
+ ar_assoc = 1;
+ break;
+ }
+ break;
+ }
+
+ dev_dbg(dev, "Association request #%02u: 0x%04x/%04x "
+ "(%zu bytes): %s\n",
+ assoc_request->AssociationDataIndex, ar_type,
+ ar_subtype, (size_t)ar_size, ar_name);
+
+ itr += sizeof(*assoc_request);
+ }
+
+ if (!ar_rhi) {
+ dev_err(dev, "Missing RETRIEVE_HOST_INFO association "
+ "request\n");
+ return -EINVAL;
+ }
+ if (!ar_assoc) {
+ dev_err(dev, "Missing ASSOCIATE association request\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct wusb_cbaf_host_info cbaf_host_info_defaults = {
+ .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
+ .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB),
+ .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+ .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO),
+ .CHID_hdr = WUSB_AR_CHID,
+ .LangID_hdr = WUSB_AR_LangID,
+ .HostFriendlyName_hdr = WUSB_AR_HostFriendlyName,
+};
+
+/* Send WUSB host information (CHID and name) to a CBAF device */
+static int cbaf_send_host_info(struct cbaf *cbaf)
+{
+ struct wusb_cbaf_host_info *hi;
+ size_t name_len;
+ size_t hi_size;
+
+ hi = cbaf->buffer;
+ memset(hi, 0, sizeof(*hi));
+ *hi = cbaf_host_info_defaults;
+ hi->CHID = cbaf->chid;
+ hi->LangID = 0; /* FIXME: I guess... */
+ strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN);
+ name_len = strlen(cbaf->host_name);
+ hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len);
+ hi_size = sizeof(*hi) + name_len;
+
+ return usb_control_msg(cbaf->usb_dev,
+ usb_sndctrlpipe(cbaf->usb_dev, 0),
+ CBAF_REQ_SET_ASSOCIATION_RESPONSE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x0101,
+ cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ hi, hi_size, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * Get device's information (CDID) associated to CHID
+ *
+ * The device will return it's information (CDID, name, bandgroups)
+ * associated to the CHID we have set before, or 0 CDID and default
+ * name and bandgroup if no CHID set or unknown.
+ */
+static int cbaf_cdid_get(struct cbaf *cbaf)
+{
+ int result;
+ struct device *dev = &cbaf->usb_iface->dev;
+ struct wusb_cbaf_device_info *di;
+ size_t needed;
+
+ di = cbaf->buffer;
+ result = usb_control_msg(
+ cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
+ CBAF_REQ_GET_ASSOCIATION_REQUEST,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ di, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "Cannot request device information: %d\n",
+ result);
+ return result;
+ }
+
+ needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length);
+ if (result < needed) {
+ dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs "
+ "%zu bytes needed)\n", (size_t)result, needed);
+ return -ENOENT;
+ }
+
+ strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN);
+ cbaf->cdid = di->CDID;
+ cbaf->device_band_groups = le16_to_cpu(di->BandGroups);
+
+ return 0;
+}
+
+static ssize_t cbaf_wusb_chid_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return sprintf(buf, "%16ph\n", cbaf->chid.data);
+}
+
+static ssize_t cbaf_wusb_chid_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx",
+ &cbaf->chid.data[0] , &cbaf->chid.data[1],
+ &cbaf->chid.data[2] , &cbaf->chid.data[3],
+ &cbaf->chid.data[4] , &cbaf->chid.data[5],
+ &cbaf->chid.data[6] , &cbaf->chid.data[7],
+ &cbaf->chid.data[8] , &cbaf->chid.data[9],
+ &cbaf->chid.data[10], &cbaf->chid.data[11],
+ &cbaf->chid.data[12], &cbaf->chid.data[13],
+ &cbaf->chid.data[14], &cbaf->chid.data[15]);
+
+ if (result != 16)
+ return -EINVAL;
+
+ result = cbaf_send_host_info(cbaf);
+ if (result < 0)
+ return result;
+ result = cbaf_cdid_get(cbaf);
+ if (result < 0)
+ return result;
+ return size;
+}
+static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store);
+
+static ssize_t cbaf_wusb_host_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name);
+}
+
+static ssize_t cbaf_wusb_host_name_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ result = sscanf(buf, "%63s", cbaf->host_name);
+ if (result != 1)
+ return -EINVAL;
+
+ return size;
+}
+static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show,
+ cbaf_wusb_host_name_store);
+
+static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups);
+}
+
+static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+ u16 band_groups = 0;
+
+ result = sscanf(buf, "%04hx", &band_groups);
+ if (result != 1)
+ return -EINVAL;
+
+ cbaf->host_band_groups = band_groups;
+
+ return size;
+}
+
+static DEVICE_ATTR(wusb_host_band_groups, 0600,
+ cbaf_wusb_host_band_groups_show,
+ cbaf_wusb_host_band_groups_store);
+
+static const struct wusb_cbaf_device_info cbaf_device_info_defaults = {
+ .Length_hdr = WUSB_AR_Length,
+ .CDID_hdr = WUSB_AR_CDID,
+ .BandGroups_hdr = WUSB_AR_BandGroups,
+ .LangID_hdr = WUSB_AR_LangID,
+ .DeviceFriendlyName_hdr = WUSB_AR_DeviceFriendlyName,
+};
+
+static ssize_t cbaf_wusb_cdid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return sprintf(buf, "%16ph\n", cbaf->cdid.data);
+}
+
+static ssize_t cbaf_wusb_cdid_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+ struct wusb_ckhdid cdid;
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx",
+ &cdid.data[0] , &cdid.data[1],
+ &cdid.data[2] , &cdid.data[3],
+ &cdid.data[4] , &cdid.data[5],
+ &cdid.data[6] , &cdid.data[7],
+ &cdid.data[8] , &cdid.data[9],
+ &cdid.data[10], &cdid.data[11],
+ &cdid.data[12], &cdid.data[13],
+ &cdid.data[14], &cdid.data[15]);
+ if (result != 16)
+ return -EINVAL;
+
+ cbaf->cdid = cdid;
+
+ return size;
+}
+static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store);
+
+static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups);
+}
+
+static DEVICE_ATTR(wusb_device_band_groups, 0600,
+ cbaf_wusb_device_band_groups_show,
+ NULL);
+
+static ssize_t cbaf_wusb_device_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name);
+}
+static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL);
+
+static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = {
+ .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
+ .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB),
+ .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+ .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE),
+ .Length_hdr = WUSB_AR_Length,
+ .Length = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)),
+ .ConnectionContext_hdr = WUSB_AR_ConnectionContext,
+ .BandGroups_hdr = WUSB_AR_BandGroups,
+};
+
+static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = {
+ .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
+ .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+ .Length_hdr = WUSB_AR_Length,
+ .AssociationStatus_hdr = WUSB_AR_AssociationStatus,
+};
+
+/*
+ * Send a new CC to the device.
+ */
+static int cbaf_cc_upload(struct cbaf *cbaf)
+{
+ int result;
+ struct device *dev = &cbaf->usb_iface->dev;
+ struct wusb_cbaf_cc_data *ccd;
+
+ ccd = cbaf->buffer;
+ *ccd = cbaf_cc_data_defaults;
+ ccd->CHID = cbaf->chid;
+ ccd->CDID = cbaf->cdid;
+ ccd->CK = cbaf->ck;
+ ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups);
+
+ dev_dbg(dev, "Trying to upload CC:\n");
+ dev_dbg(dev, " CHID %16ph\n", ccd->CHID.data);
+ dev_dbg(dev, " CDID %16ph\n", ccd->CDID.data);
+ dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups);
+
+ result = usb_control_msg(
+ cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0),
+ CBAF_REQ_SET_ASSOCIATION_RESPONSE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ ccd, sizeof(*ccd), USB_CTRL_SET_TIMEOUT);
+
+ return result;
+}
+
+static ssize_t cbaf_wusb_ck_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx",
+ &cbaf->ck.data[0] , &cbaf->ck.data[1],
+ &cbaf->ck.data[2] , &cbaf->ck.data[3],
+ &cbaf->ck.data[4] , &cbaf->ck.data[5],
+ &cbaf->ck.data[6] , &cbaf->ck.data[7],
+ &cbaf->ck.data[8] , &cbaf->ck.data[9],
+ &cbaf->ck.data[10], &cbaf->ck.data[11],
+ &cbaf->ck.data[12], &cbaf->ck.data[13],
+ &cbaf->ck.data[14], &cbaf->ck.data[15]);
+ if (result != 16)
+ return -EINVAL;
+
+ result = cbaf_cc_upload(cbaf);
+ if (result < 0)
+ return result;
+
+ return size;
+}
+static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store);
+
+static struct attribute *cbaf_dev_attrs[] = {
+ &dev_attr_wusb_host_name.attr,
+ &dev_attr_wusb_host_band_groups.attr,
+ &dev_attr_wusb_chid.attr,
+ &dev_attr_wusb_cdid.attr,
+ &dev_attr_wusb_device_name.attr,
+ &dev_attr_wusb_device_band_groups.attr,
+ &dev_attr_wusb_ck.attr,
+ NULL,
+};
+
+static const struct attribute_group cbaf_dev_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = cbaf_dev_attrs,
+};
+
+static int cbaf_probe(struct usb_interface *iface,
+ const struct usb_device_id *id)
+{
+ struct cbaf *cbaf;
+ struct device *dev = &iface->dev;
+ int result = -ENOMEM;
+
+ cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL);
+ if (cbaf == NULL)
+ goto error_kzalloc;
+ cbaf->buffer = kmalloc(512, GFP_KERNEL);
+ if (cbaf->buffer == NULL)
+ goto error_kmalloc_buffer;
+
+ cbaf->buffer_size = 512;
+ cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface));
+ cbaf->usb_iface = usb_get_intf(iface);
+ result = cbaf_check(cbaf);
+ if (result < 0) {
+ dev_err(dev, "This device is not WUSB-CBAF compliant and is not supported yet.\n");
+ goto error_check;
+ }
+
+ result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group);
+ if (result < 0) {
+ dev_err(dev, "Can't register sysfs attr group: %d\n", result);
+ goto error_create_group;
+ }
+ usb_set_intfdata(iface, cbaf);
+ return 0;
+
+error_create_group:
+error_check:
+ usb_put_intf(iface);
+ usb_put_dev(cbaf->usb_dev);
+ kfree(cbaf->buffer);
+error_kmalloc_buffer:
+ kfree(cbaf);
+error_kzalloc:
+ return result;
+}
+
+static void cbaf_disconnect(struct usb_interface *iface)
+{
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+ struct device *dev = &iface->dev;
+ sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group);
+ usb_set_intfdata(iface, NULL);
+ usb_put_intf(iface);
+ usb_put_dev(cbaf->usb_dev);
+ kfree(cbaf->buffer);
+ /* paranoia: clean up crypto keys */
+ kzfree(cbaf);
+}
+
+static const struct usb_device_id cbaf_id_table[] = {
+ { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, cbaf_id_table);
+
+static struct usb_driver cbaf_driver = {
+ .name = "wusb-cbaf",
+ .id_table = cbaf_id_table,
+ .probe = cbaf_probe,
+ .disconnect = cbaf_disconnect,
+};
+
+module_usb_driver(cbaf_driver);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB Cable Based Association");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/crypto.c b/drivers/staging/wusbcore/crypto.c
new file mode 100644
index 000000000000..d7d55ed19a98
--- /dev/null
+++ b/drivers/staging/wusbcore/crypto.c
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ultra Wide Band
+ * AES-128 CCM Encryption
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * We don't do any encryption here; we use the Linux Kernel's AES-128
+ * crypto modules to construct keys and payload blocks in a way
+ * defined by WUSB1.0[6]. Check the erratas, as typos are are patched
+ * there.
+ *
+ * Thanks a zillion to John Keys for his help and clarifications over
+ * the designed-by-a-committee text.
+ *
+ * So the idea is that there is this basic Pseudo-Random-Function
+ * defined in WUSB1.0[6.5] which is the core of everything. It works
+ * by tweaking some blocks, AES crypting them and then xoring
+ * something else with them (this seems to be called CBC(AES) -- can
+ * you tell I know jack about crypto?). So we just funnel it into the
+ * Linux Crypto API.
+ *
+ * We leave a crypto test module so we can verify that vectors match,
+ * every now and then.
+ *
+ * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I
+ * am learning a lot...
+ *
+ * Conveniently, some data structures that need to be
+ * funneled through AES are...16 bytes in size!
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/skcipher.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include "../uwb/uwb.h"
+#include "include/wusb.h"
+
+static int debug_crypto_verify;
+
+module_param(debug_crypto_verify, int, 0);
+MODULE_PARM_DESC(debug_crypto_verify, "verify the key generation algorithms");
+
+static void wusb_key_dump(const void *buf, size_t len)
+{
+ print_hex_dump(KERN_ERR, " ", DUMP_PREFIX_OFFSET, 16, 1,
+ buf, len, 0);
+}
+
+/*
+ * Block of data, as understood by AES-CCM
+ *
+ * The code assumes this structure is nothing but a 16 byte array
+ * (packed in a struct to avoid common mess ups that I usually do with
+ * arrays and enforcing type checking).
+ */
+struct aes_ccm_block {
+ u8 data[16];
+} __attribute__((packed));
+
+/*
+ * Counter-mode Blocks (WUSB1.0[6.4])
+ *
+ * According to CCM (or so it seems), for the purpose of calculating
+ * the MIC, the message is broken in N counter-mode blocks, B0, B1,
+ * ... BN.
+ *
+ * B0 contains flags, the CCM nonce and l(m).
+ *
+ * B1 contains l(a), the MAC header, the encryption offset and padding.
+ *
+ * If EO is nonzero, additional blocks are built from payload bytes
+ * until EO is exhausted (FIXME: padding to 16 bytes, I guess). The
+ * padding is not xmitted.
+ */
+
+/* WUSB1.0[T6.4] */
+struct aes_ccm_b0 {
+ u8 flags; /* 0x59, per CCM spec */
+ struct aes_ccm_nonce ccm_nonce;
+ __be16 lm;
+} __attribute__((packed));
+
+/* WUSB1.0[T6.5] */
+struct aes_ccm_b1 {
+ __be16 la;
+ u8 mac_header[10];
+ __le16 eo;
+ u8 security_reserved; /* This is always zero */
+ u8 padding; /* 0 */
+} __attribute__((packed));
+
+/*
+ * Encryption Blocks (WUSB1.0[6.4.4])
+ *
+ * CCM uses Ax blocks to generate a keystream with which the MIC and
+ * the message's payload are encoded. A0 always encrypts/decrypts the
+ * MIC. Ax (x>0) are used for the successive payload blocks.
+ *
+ * The x is the counter, and is increased for each block.
+ */
+struct aes_ccm_a {
+ u8 flags; /* 0x01, per CCM spec */
+ struct aes_ccm_nonce ccm_nonce;
+ __be16 counter; /* Value of x */
+} __attribute__((packed));
+
+/* Scratch space for MAC calculations. */
+struct wusb_mac_scratch {
+ struct aes_ccm_b0 b0;
+ struct aes_ccm_b1 b1;
+ struct aes_ccm_a ax;
+};
+
+/*
+ * CC-MAC function WUSB1.0[6.5]
+ *
+ * Take a data string and produce the encrypted CBC Counter-mode MIC
+ *
+ * Note the names for most function arguments are made to (more or
+ * less) match those used in the pseudo-function definition given in
+ * WUSB1.0[6.5].
+ *
+ * @tfm_cbc: CBC(AES) blkcipher handle (initialized)
+ *
+ * @tfm_aes: AES cipher handle (initialized)
+ *
+ * @mic: buffer for placing the computed MIC (Message Integrity
+ * Code). This is exactly 8 bytes, and we expect the buffer to
+ * be at least eight bytes in length.
+ *
+ * @key: 128 bit symmetric key
+ *
+ * @n: CCM nonce
+ *
+ * @a: ASCII string, 14 bytes long (I guess zero padded if needed;
+ * we use exactly 14 bytes).
+ *
+ * @b: data stream to be processed
+ *
+ * @blen: size of b...
+ *
+ * Still not very clear how this is done, but looks like this: we
+ * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with
+ * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we
+ * take the payload and divide it in blocks (16 bytes), xor them with
+ * the previous crypto result (16 bytes) and crypt it, repeat the next
+ * block with the output of the previous one, rinse wash. So we use
+ * the CBC-MAC(AES) shash, that does precisely that. The IV (Initial
+ * Vector) is 16 bytes and is set to zero, so
+ *
+ * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and
+ * using the 14 bytes of @a to fill up
+ * b1.{mac_header,e0,security_reserved,padding}.
+ *
+ * NOTE: The definition of l(a) in WUSB1.0[6.5] vs the definition of
+ * l(m) is orthogonal, they bear no relationship, so it is not
+ * in conflict with the parameter's relation that
+ * WUSB1.0[6.4.2]) defines.
+ *
+ * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in
+ * first errata released on 2005/07.
+ *
+ * NOTE: we need to clean IV to zero at each invocation to make sure
+ * we start with a fresh empty Initial Vector, so that the CBC
+ * works ok.
+ *
+ * NOTE: blen is not aligned to a block size, we'll pad zeros, that's
+ * what sg[4] is for. Maybe there is a smarter way to do this.
+ */
+static int wusb_ccm_mac(struct crypto_shash *tfm_cbcmac,
+ struct wusb_mac_scratch *scratch,
+ void *mic,
+ const struct aes_ccm_nonce *n,
+ const struct aes_ccm_label *a, const void *b,
+ size_t blen)
+{
+ SHASH_DESC_ON_STACK(desc, tfm_cbcmac);
+ u8 iv[AES_BLOCK_SIZE];
+
+ /*
+ * These checks should be compile time optimized out
+ * ensure @a fills b1's mac_header and following fields
+ */
+ BUILD_BUG_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
+ BUILD_BUG_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
+ BUILD_BUG_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
+ BUILD_BUG_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
+
+ /* Setup B0 */
+ scratch->b0.flags = 0x59; /* Format B0 */
+ scratch->b0.ccm_nonce = *n;
+ scratch->b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */
+
+ /* Setup B1
+ *
+ * The WUSB spec is anything but clear! WUSB1.0[6.5]
+ * says that to initialize B1 from A with 'l(a) = blen +
+ * 14'--after clarification, it means to use A's contents
+ * for MAC Header, EO, sec reserved and padding.
+ */
+ scratch->b1.la = cpu_to_be16(blen + 14);
+ memcpy(&scratch->b1.mac_header, a, sizeof(*a));
+
+ desc->tfm = tfm_cbcmac;
+ crypto_shash_init(desc);
+ crypto_shash_update(desc, (u8 *)&scratch->b0, sizeof(scratch->b0) +
+ sizeof(scratch->b1));
+ crypto_shash_finup(desc, b, blen, iv);
+
+ /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5]
+ * The procedure is to AES crypt the A0 block and XOR the MIC
+ * Tag against it; we only do the first 8 bytes and place it
+ * directly in the destination buffer.
+ */
+ scratch->ax.flags = 0x01; /* as per WUSB 1.0 spec */
+ scratch->ax.ccm_nonce = *n;
+ scratch->ax.counter = 0;
+
+ /* reuse the CBC-MAC transform to perform the single block encryption */
+ crypto_shash_digest(desc, (u8 *)&scratch->ax, sizeof(scratch->ax),
+ (u8 *)&scratch->ax);
+
+ crypto_xor_cpy(mic, (u8 *)&scratch->ax, iv, 8);
+
+ return 8;
+}
+
+/*
+ * WUSB Pseudo Random Function (WUSB1.0[6.5])
+ *
+ * @b: buffer to the source data; cannot be a global or const local
+ * (will confuse the scatterlists)
+ */
+ssize_t wusb_prf(void *out, size_t out_size,
+ const u8 key[16], const struct aes_ccm_nonce *_n,
+ const struct aes_ccm_label *a,
+ const void *b, size_t blen, size_t len)
+{
+ ssize_t result, bytes = 0, bitr;
+ struct aes_ccm_nonce n = *_n;
+ struct crypto_shash *tfm_cbcmac;
+ struct wusb_mac_scratch scratch;
+ u64 sfn = 0;
+ __le64 sfn_le;
+
+ tfm_cbcmac = crypto_alloc_shash("cbcmac(aes)", 0, 0);
+ if (IS_ERR(tfm_cbcmac)) {
+ result = PTR_ERR(tfm_cbcmac);
+ printk(KERN_ERR "E: can't load CBCMAC-AES: %d\n", (int)result);
+ goto error_alloc_cbcmac;
+ }
+
+ result = crypto_shash_setkey(tfm_cbcmac, key, AES_BLOCK_SIZE);
+ if (result < 0) {
+ printk(KERN_ERR "E: can't set CBCMAC-AES key: %d\n", (int)result);
+ goto error_setkey_cbcmac;
+ }
+
+ for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
+ sfn_le = cpu_to_le64(sfn++);
+ memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
+ result = wusb_ccm_mac(tfm_cbcmac, &scratch, out + bytes,
+ &n, a, b, blen);
+ if (result < 0)
+ goto error_ccm_mac;
+ bytes += result;
+ }
+ result = bytes;
+
+error_ccm_mac:
+error_setkey_cbcmac:
+ crypto_free_shash(tfm_cbcmac);
+error_alloc_cbcmac:
+ return result;
+}
+
+/* WUSB1.0[A.2] test vectors */
+static const u8 stv_hsmic_key[16] = {
+ 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
+ 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
+};
+
+static const struct aes_ccm_nonce stv_hsmic_n = {
+ .sfn = { 0 },
+ .tkid = { 0x76, 0x98, 0x01, },
+ .dest_addr = { .data = { 0xbe, 0x00 } },
+ .src_addr = { .data = { 0x76, 0x98 } },
+};
+
+/*
+ * Out-of-band MIC Generation verification code
+ *
+ */
+static int wusb_oob_mic_verify(void)
+{
+ int result;
+ u8 mic[8];
+ /* WUSB1.0[A.2] test vectors */
+ static const struct usb_handshake stv_hsmic_hs = {
+ .bMessageNumber = 2,
+ .bStatus = 00,
+ .tTKID = { 0x76, 0x98, 0x01 },
+ .bReserved = 00,
+ .CDID = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+ 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f },
+ .nonce = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x2c, 0x2d, 0x2e, 0x2f },
+ .MIC = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c,
+ 0x14, 0x7b },
+ };
+ size_t hs_size;
+
+ result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs);
+ if (result < 0)
+ printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result);
+ else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) {
+ printk(KERN_ERR "E: OOB MIC test: "
+ "mismatch between MIC result and WUSB1.0[A2]\n");
+ hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC);
+ printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size);
+ wusb_key_dump(&stv_hsmic_hs, hs_size);
+ printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n",
+ sizeof(stv_hsmic_n));
+ wusb_key_dump(&stv_hsmic_n, sizeof(stv_hsmic_n));
+ printk(KERN_ERR "E: MIC out:\n");
+ wusb_key_dump(mic, sizeof(mic));
+ printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n");
+ wusb_key_dump(stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC));
+ result = -EINVAL;
+ } else
+ result = 0;
+ return result;
+}
+
+/*
+ * Test vectors for Key derivation
+ *
+ * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1]
+ * (errata corrected in 2005/07).
+ */
+static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = {
+ 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
+ 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f
+};
+
+static const struct aes_ccm_nonce stv_keydvt_n_a1 = {
+ .sfn = { 0 },
+ .tkid = { 0x76, 0x98, 0x01, },
+ .dest_addr = { .data = { 0xbe, 0x00 } },
+ .src_addr = { .data = { 0x76, 0x98 } },
+};
+
+static const struct wusb_keydvt_out stv_keydvt_out_a1 = {
+ .kck = {
+ 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
+ 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
+ },
+ .ptk = {
+ 0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06,
+ 0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d
+ }
+};
+
+/*
+ * Performa a test to make sure we match the vectors defined in
+ * WUSB1.0[A.1](Errata2006/12)
+ */
+static int wusb_key_derive_verify(void)
+{
+ int result = 0;
+ struct wusb_keydvt_out keydvt_out;
+ /* These come from WUSB1.0[A.1] + 2006/12 errata */
+ static const struct wusb_keydvt_in stv_keydvt_in_a1 = {
+ .hnonce = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+ },
+ .dnonce = {
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
+ }
+ };
+
+ result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1,
+ &stv_keydvt_in_a1);
+ if (result < 0)
+ printk(KERN_ERR "E: WUSB key derivation test: "
+ "derivation failed: %d\n", result);
+ if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) {
+ printk(KERN_ERR "E: WUSB key derivation test: "
+ "mismatch between key derivation result "
+ "and WUSB1.0[A1] Errata 2006/12\n");
+ printk(KERN_ERR "E: keydvt in: key\n");
+ wusb_key_dump(stv_key_a1, sizeof(stv_key_a1));
+ printk(KERN_ERR "E: keydvt in: nonce\n");
+ wusb_key_dump(&stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1));
+ printk(KERN_ERR "E: keydvt in: hnonce & dnonce\n");
+ wusb_key_dump(&stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1));
+ printk(KERN_ERR "E: keydvt out: KCK\n");
+ wusb_key_dump(&keydvt_out.kck, sizeof(keydvt_out.kck));
+ printk(KERN_ERR "E: keydvt out: PTK\n");
+ wusb_key_dump(&keydvt_out.ptk, sizeof(keydvt_out.ptk));
+ result = -EINVAL;
+ } else
+ result = 0;
+ return result;
+}
+
+/*
+ * Initialize crypto system
+ *
+ * FIXME: we do nothing now, other than verifying. Later on we'll
+ * cache the encryption stuff, so that's why we have a separate init.
+ */
+int wusb_crypto_init(void)
+{
+ int result;
+
+ if (debug_crypto_verify) {
+ result = wusb_key_derive_verify();
+ if (result < 0)
+ return result;
+ return wusb_oob_mic_verify();
+ }
+ return 0;
+}
+
+void wusb_crypto_exit(void)
+{
+ /* FIXME: free cached crypto transforms */
+}
diff --git a/drivers/staging/wusbcore/dev-sysfs.c b/drivers/staging/wusbcore/dev-sysfs.c
new file mode 100644
index 000000000000..67b0a4c412b2
--- /dev/null
+++ b/drivers/staging/wusbcore/dev-sysfs.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB devices
+ * sysfs bindings
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Get them out of the way...
+ */
+
+#include <linux/jiffies.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include "wusbhc.h"
+
+static ssize_t wusb_disconnect_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct usb_device *usb_dev;
+ struct wusbhc *wusbhc;
+ unsigned command;
+ u8 port_idx;
+
+ if (sscanf(buf, "%u", &command) != 1)
+ return -EINVAL;
+ if (command == 0)
+ return size;
+ usb_dev = to_usb_device(dev);
+ wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+ if (wusbhc == NULL)
+ return -ENODEV;
+
+ mutex_lock(&wusbhc->mutex);
+ port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+ __wusbhc_dev_disable(wusbhc, port_idx);
+ mutex_unlock(&wusbhc->mutex);
+ wusbhc_put(wusbhc);
+ return size;
+}
+static DEVICE_ATTR_WO(wusb_disconnect);
+
+static ssize_t wusb_cdid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t result;
+ struct wusb_dev *wusb_dev;
+
+ wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev));
+ if (wusb_dev == NULL)
+ return -ENODEV;
+ result = sprintf(buf, "%16ph\n", wusb_dev->cdid.data);
+ wusb_dev_put(wusb_dev);
+ return result;
+}
+static DEVICE_ATTR_RO(wusb_cdid);
+
+static ssize_t wusb_ck_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int result;
+ struct usb_device *usb_dev;
+ struct wusbhc *wusbhc;
+ struct wusb_ckhdid ck;
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx\n",
+ &ck.data[0] , &ck.data[1],
+ &ck.data[2] , &ck.data[3],
+ &ck.data[4] , &ck.data[5],
+ &ck.data[6] , &ck.data[7],
+ &ck.data[8] , &ck.data[9],
+ &ck.data[10], &ck.data[11],
+ &ck.data[12], &ck.data[13],
+ &ck.data[14], &ck.data[15]);
+ if (result != 16)
+ return -EINVAL;
+
+ usb_dev = to_usb_device(dev);
+ wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+ if (wusbhc == NULL)
+ return -ENODEV;
+ result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck);
+ memzero_explicit(&ck, sizeof(ck));
+ wusbhc_put(wusbhc);
+ return result < 0 ? result : size;
+}
+static DEVICE_ATTR_WO(wusb_ck);
+
+static struct attribute *wusb_dev_attrs[] = {
+ &dev_attr_wusb_disconnect.attr,
+ &dev_attr_wusb_cdid.attr,
+ &dev_attr_wusb_ck.attr,
+ NULL,
+};
+
+static const struct attribute_group wusb_dev_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = wusb_dev_attrs,
+};
+
+int wusb_dev_sysfs_add(struct wusbhc *wusbhc, struct usb_device *usb_dev,
+ struct wusb_dev *wusb_dev)
+{
+ int result = sysfs_create_group(&usb_dev->dev.kobj,
+ &wusb_dev_attr_group);
+ struct device *dev = &usb_dev->dev;
+ if (result < 0)
+ dev_err(dev, "Cannot register WUSB-dev attributes: %d\n",
+ result);
+ return result;
+}
+
+void wusb_dev_sysfs_rm(struct wusb_dev *wusb_dev)
+{
+ struct usb_device *usb_dev = wusb_dev->usb_dev;
+ if (usb_dev)
+ sysfs_remove_group(&usb_dev->dev.kobj, &wusb_dev_attr_group);
+}
diff --git a/drivers/staging/wusbcore/devconnect.c b/drivers/staging/wusbcore/devconnect.c
new file mode 100644
index 000000000000..1170f8baf608
--- /dev/null
+++ b/drivers/staging/wusbcore/devconnect.c
@@ -0,0 +1,1085 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * Device Connect handling
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ * FIXME: this file needs to be broken up, it's grown too big
+ *
+ *
+ * WUSB1.0[7.1, 7.5.1, ]
+ *
+ * WUSB device connection is kind of messy. Some background:
+ *
+ * When a device wants to connect it scans the UWB radio channels
+ * looking for a WUSB Channel; a WUSB channel is defined by MMCs
+ * (Micro Managed Commands or something like that) [see
+ * Design-overview for more on this] .
+ *
+ * So, device scans the radio, finds MMCs and thus a host and checks
+ * when the next DNTS is. It sends a Device Notification Connect
+ * (DN_Connect); the host picks it up (through nep.c and notif.c, ends
+ * up in wusb_devconnect_ack(), which creates a wusb_dev structure in
+ * wusbhc->port[port_number].wusb_dev), assigns an unauth address
+ * to the device (this means from 0x80 to 0xfe) and sends, in the MMC
+ * a Connect Ack Information Element (ConnAck IE).
+ *
+ * So now the device now has a WUSB address. From now on, we use
+ * that to talk to it in the RPipes.
+ *
+ * ASSUMPTIONS:
+ *
+ * - We use the the as device address the port number where it is
+ * connected (port 0 doesn't exist). For unauth, it is 128 + that.
+ *
+ * ROADMAP:
+ *
+ * This file contains the logic for doing that--entry points:
+ *
+ * wusb_devconnect_ack() Ack a device until _acked() called.
+ * Called by notif.c:wusb_handle_dn_connect()
+ * when a DN_Connect is received.
+ *
+ * wusb_devconnect_acked() Ack done, release resources.
+ *
+ * wusb_handle_dn_alive() Called by notif.c:wusb_handle_dn()
+ * for processing a DN_Alive pong from a device.
+ *
+ * wusb_handle_dn_disconnect()Called by notif.c:wusb_handle_dn() to
+ * process a disconnect request from a
+ * device.
+ *
+ * __wusb_dev_disable() Called by rh.c:wusbhc_rh_clear_port_feat() when
+ * disabling a port.
+ *
+ * wusb_devconnect_create() Called when creating the host by
+ * lc.c:wusbhc_create().
+ *
+ * wusb_devconnect_destroy() Cleanup called removing the host. Called
+ * by lc.c:wusbhc_destroy().
+ *
+ * Each Wireless USB host maintains a list of DN_Connect requests
+ * (actually we maintain a list of pending Connect Acks, the
+ * wusbhc->ca_list).
+ *
+ * LIFE CYCLE OF port->wusb_dev
+ *
+ * Before the @wusbhc structure put()s the reference it owns for
+ * port->wusb_dev [and clean the wusb_dev pointer], it needs to
+ * lock @wusbhc->mutex.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include "wusbhc.h"
+
+static void wusbhc_devconnect_acked_work(struct work_struct *work);
+
+static void wusb_dev_free(struct wusb_dev *wusb_dev)
+{
+ kfree(wusb_dev);
+}
+
+static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
+{
+ struct wusb_dev *wusb_dev;
+
+ wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL);
+ if (wusb_dev == NULL)
+ goto err;
+
+ wusb_dev->wusbhc = wusbhc;
+
+ INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work);
+
+ return wusb_dev;
+err:
+ wusb_dev_free(wusb_dev);
+ return NULL;
+}
+
+
+/*
+ * Using the Connect-Ack list, fill out the @wusbhc Connect-Ack WUSB IE
+ * properly so that it can be added to the MMC.
+ *
+ * We just get the @wusbhc->ca_list and fill out the first four ones or
+ * less (per-spec WUSB1.0[7.5, before T7-38). If the ConnectAck WUSB
+ * IE is not allocated, we alloc it.
+ *
+ * @wusbhc->mutex must be taken
+ */
+static void wusbhc_fill_cack_ie(struct wusbhc *wusbhc)
+{
+ unsigned cnt;
+ struct wusb_dev *dev_itr;
+ struct wuie_connect_ack *cack_ie;
+
+ cack_ie = &wusbhc->cack_ie;
+ cnt = 0;
+ list_for_each_entry(dev_itr, &wusbhc->cack_list, cack_node) {
+ cack_ie->blk[cnt].CDID = dev_itr->cdid;
+ cack_ie->blk[cnt].bDeviceAddress = dev_itr->addr;
+ if (++cnt >= WUIE_ELT_MAX)
+ break;
+ }
+ cack_ie->hdr.bLength = sizeof(cack_ie->hdr)
+ + cnt * sizeof(cack_ie->blk[0]);
+}
+
+/*
+ * Register a new device that wants to connect
+ *
+ * A new device wants to connect, so we add it to the Connect-Ack
+ * list. We give it an address in the unauthorized range (bit 8 set);
+ * user space will have to drive authorization further on.
+ *
+ * @dev_addr: address to use for the device (which is also the port
+ * number).
+ *
+ * @wusbhc->mutex must be taken
+ */
+static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc,
+ struct wusb_dn_connect *dnc,
+ const char *pr_cdid, u8 port_idx)
+{
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+ int new_connection = wusb_dn_connect_new_connection(dnc);
+ u8 dev_addr;
+ int result;
+
+ /* Is it registered already? */
+ list_for_each_entry(wusb_dev, &wusbhc->cack_list, cack_node)
+ if (!memcmp(&wusb_dev->cdid, &dnc->CDID,
+ sizeof(wusb_dev->cdid)))
+ return wusb_dev;
+ /* We don't have it, create an entry, register it */
+ wusb_dev = wusb_dev_alloc(wusbhc);
+ if (wusb_dev == NULL)
+ return NULL;
+ wusb_dev_init(wusb_dev);
+ wusb_dev->cdid = dnc->CDID;
+ wusb_dev->port_idx = port_idx;
+
+ /*
+ * Devices are always available within the cluster reservation
+ * and since the hardware will take the intersection of the
+ * per-device availability and the cluster reservation, the
+ * per-device availability can simply be set to always
+ * available.
+ */
+ bitmap_fill(wusb_dev->availability.bm, UWB_NUM_MAS);
+
+ /* FIXME: handle reconnects instead of assuming connects are
+ always new. */
+ if (1 && new_connection == 0)
+ new_connection = 1;
+ if (new_connection) {
+ dev_addr = (port_idx + 2) | WUSB_DEV_ADDR_UNAUTH;
+
+ dev_info(dev, "Connecting new WUSB device to address %u, "
+ "port %u\n", dev_addr, port_idx);
+
+ result = wusb_set_dev_addr(wusbhc, wusb_dev, dev_addr);
+ if (result < 0)
+ return NULL;
+ }
+ wusb_dev->entry_ts = jiffies;
+ list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list);
+ wusbhc->cack_count++;
+ wusbhc_fill_cack_ie(wusbhc);
+
+ return wusb_dev;
+}
+
+/*
+ * Remove a Connect-Ack context entry from the HCs view
+ *
+ * @wusbhc->mutex must be taken
+ */
+static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ list_del_init(&wusb_dev->cack_node);
+ wusbhc->cack_count--;
+ wusbhc_fill_cack_ie(wusbhc);
+}
+
+/*
+ * @wusbhc->mutex must be taken */
+static
+void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ wusbhc_cack_rm(wusbhc, wusb_dev);
+ if (wusbhc->cack_count)
+ wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
+ else
+ wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr);
+}
+
+static void wusbhc_devconnect_acked_work(struct work_struct *work)
+{
+ struct wusb_dev *wusb_dev = container_of(work, struct wusb_dev,
+ devconnect_acked_work);
+ struct wusbhc *wusbhc = wusb_dev->wusbhc;
+
+ mutex_lock(&wusbhc->mutex);
+ wusbhc_devconnect_acked(wusbhc, wusb_dev);
+ mutex_unlock(&wusbhc->mutex);
+
+ wusb_dev_put(wusb_dev);
+}
+
+/*
+ * Ack a device for connection
+ *
+ * FIXME: docs
+ *
+ * @pr_cdid: Printable CDID...hex Use @dnc->cdid for the real deal.
+ *
+ * So we get the connect ack IE (may have been allocated already),
+ * find an empty connect block, an empty virtual port, create an
+ * address with it (see below), make it an unauth addr [bit 7 set] and
+ * set the MMC.
+ *
+ * Addresses: because WUSB hosts have no downstream hubs, we can do a
+ * 1:1 mapping between 'port number' and device
+ * address. This simplifies many things, as during this
+ * initial connect phase the USB stack has no knowledge of
+ * the device and hasn't assigned an address yet--we know
+ * USB's choose_address() will use the same heuristics we
+ * use here, so we can assume which address will be assigned.
+ *
+ * USB stack always assigns address 1 to the root hub, so
+ * to the port number we add 2 (thus virtual port #0 is
+ * addr #2).
+ *
+ * @wusbhc shall be referenced
+ */
+static
+void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,
+ const char *pr_cdid)
+{
+ int result;
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+ struct wusb_port *port;
+ unsigned idx;
+
+ mutex_lock(&wusbhc->mutex);
+
+ /* Check we are not handling it already */
+ for (idx = 0; idx < wusbhc->ports_max; idx++) {
+ port = wusb_port_by_idx(wusbhc, idx);
+ if (port->wusb_dev
+ && memcmp(&dnc->CDID, &port->wusb_dev->cdid, sizeof(dnc->CDID)) == 0)
+ goto error_unlock;
+ }
+ /* Look up those fake ports we have for a free one */
+ for (idx = 0; idx < wusbhc->ports_max; idx++) {
+ port = wusb_port_by_idx(wusbhc, idx);
+ if ((port->status & USB_PORT_STAT_POWER)
+ && !(port->status & USB_PORT_STAT_CONNECTION))
+ break;
+ }
+ if (idx >= wusbhc->ports_max) {
+ dev_err(dev, "Host controller can't connect more devices "
+ "(%u already connected); device %s rejected\n",
+ wusbhc->ports_max, pr_cdid);
+ /* NOTE: we could send a WUIE_Disconnect here, but we haven't
+ * event acked, so the device will eventually timeout the
+ * connection, right? */
+ goto error_unlock;
+ }
+
+ /* Make sure we are using no crypto on that "virtual port" */
+ wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0);
+
+ /* Grab a filled in Connect-Ack context, fill out the
+ * Connect-Ack Wireless USB IE, set the MMC */
+ wusb_dev = wusbhc_cack_add(wusbhc, dnc, pr_cdid, idx);
+ if (wusb_dev == NULL)
+ goto error_unlock;
+ result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
+ if (result < 0)
+ goto error_unlock;
+ /* Give the device at least 2ms (WUSB1.0[7.5.1p3]), let's do
+ * three for a good measure */
+ msleep(3);
+ port->wusb_dev = wusb_dev;
+ port->status |= USB_PORT_STAT_CONNECTION;
+ port->change |= USB_PORT_STAT_C_CONNECTION;
+ /* Now the port status changed to connected; hub_wq will
+ * pick the change up and try to reset the port to bring it to
+ * the enabled state--so this process returns up to the stack
+ * and it calls back into wusbhc_rh_port_reset().
+ */
+error_unlock:
+ mutex_unlock(&wusbhc->mutex);
+ return;
+
+}
+
+/*
+ * Disconnect a Wireless USB device from its fake port
+ *
+ * Marks the port as disconnected so that hub_wq can pick up the change
+ * and drops our knowledge about the device.
+ *
+ * Assumes there is a device connected
+ *
+ * @port_index: zero based port number
+ *
+ * NOTE: @wusbhc->mutex is locked
+ *
+ * WARNING: From here it is not very safe to access anything hanging off
+ * wusb_dev
+ */
+static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc,
+ struct wusb_port *port)
+{
+ struct wusb_dev *wusb_dev = port->wusb_dev;
+
+ port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE
+ | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET
+ | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
+ port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE;
+ if (wusb_dev) {
+ dev_dbg(wusbhc->dev, "disconnecting device from port %d\n", wusb_dev->port_idx);
+ if (!list_empty(&wusb_dev->cack_node))
+ list_del_init(&wusb_dev->cack_node);
+ /* For the one in cack_add() */
+ wusb_dev_put(wusb_dev);
+ }
+ port->wusb_dev = NULL;
+
+ /* After a device disconnects, change the GTK (see [WUSB]
+ * section 6.2.11.2). */
+ if (wusbhc->active)
+ wusbhc_gtk_rekey(wusbhc);
+
+ /* The Wireless USB part has forgotten about the device already; now
+ * hub_wq's timer will pick up the disconnection and remove the USB
+ * device from the system
+ */
+}
+
+/*
+ * Refresh the list of keep alives to emit in the MMC
+ *
+ * We only publish the first four devices that have a coming timeout
+ * condition. Then when we are done processing those, we go for the
+ * next ones. We ignore the ones that have timed out already (they'll
+ * be purged).
+ *
+ * This might cause the first devices to timeout the last devices in
+ * the port array...FIXME: come up with a better algorithm?
+ *
+ * Note we can't do much about MMC's ops errors; we hope next refresh
+ * will kind of handle it.
+ *
+ * NOTE: @wusbhc->mutex is locked
+ */
+static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
+{
+ struct device *dev = wusbhc->dev;
+ unsigned cnt;
+ struct wusb_dev *wusb_dev;
+ struct wusb_port *wusb_port;
+ struct wuie_keep_alive *ie = &wusbhc->keep_alive_ie;
+ unsigned keep_alives, old_keep_alives;
+
+ old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr);
+ keep_alives = 0;
+ for (cnt = 0;
+ keep_alives < WUIE_ELT_MAX && cnt < wusbhc->ports_max;
+ cnt++) {
+ unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout);
+
+ wusb_port = wusb_port_by_idx(wusbhc, cnt);
+ wusb_dev = wusb_port->wusb_dev;
+
+ if (wusb_dev == NULL)
+ continue;
+ if (wusb_dev->usb_dev == NULL)
+ continue;
+
+ if (time_after(jiffies, wusb_dev->entry_ts + tt)) {
+ dev_err(dev, "KEEPALIVE: device %u timed out\n",
+ wusb_dev->addr);
+ __wusbhc_dev_disconnect(wusbhc, wusb_port);
+ } else if (time_after(jiffies, wusb_dev->entry_ts + tt/3)) {
+ /* Approaching timeout cut off, need to refresh */
+ ie->bDeviceAddress[keep_alives++] = wusb_dev->addr;
+ }
+ }
+ if (keep_alives & 0x1) /* pad to even number ([WUSB] section 7.5.9) */
+ ie->bDeviceAddress[keep_alives++] = 0x7f;
+ ie->hdr.bLength = sizeof(ie->hdr) +
+ keep_alives*sizeof(ie->bDeviceAddress[0]);
+ if (keep_alives > 0)
+ wusbhc_mmcie_set(wusbhc, 10, 5, &ie->hdr);
+ else if (old_keep_alives != 0)
+ wusbhc_mmcie_rm(wusbhc, &ie->hdr);
+}
+
+/*
+ * Do a run through all devices checking for timeouts
+ */
+static void wusbhc_keep_alive_run(struct work_struct *ws)
+{
+ struct delayed_work *dw = to_delayed_work(ws);
+ struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer);
+
+ mutex_lock(&wusbhc->mutex);
+ __wusbhc_keep_alive(wusbhc);
+ mutex_unlock(&wusbhc->mutex);
+
+ queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+ msecs_to_jiffies(wusbhc->trust_timeout / 2));
+}
+
+/*
+ * Find the wusb_dev from its device address.
+ *
+ * The device can be found directly from the address (see
+ * wusb_cack_add() for where the device address is set to port_idx
+ * +2), except when the address is zero.
+ */
+static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
+{
+ int p;
+
+ if (addr == 0xff) /* unconnected */
+ return NULL;
+
+ if (addr > 0) {
+ int port = (addr & ~0x80) - 2;
+ if (port < 0 || port >= wusbhc->ports_max)
+ return NULL;
+ return wusb_port_by_idx(wusbhc, port)->wusb_dev;
+ }
+
+ /* Look for the device with address 0. */
+ for (p = 0; p < wusbhc->ports_max; p++) {
+ struct wusb_dev *wusb_dev = wusb_port_by_idx(wusbhc, p)->wusb_dev;
+ if (wusb_dev && wusb_dev->addr == addr)
+ return wusb_dev;
+ }
+ return NULL;
+}
+
+/*
+ * Handle a DN_Alive notification (WUSB1.0[7.6.1])
+ *
+ * This just updates the device activity timestamp and then refreshes
+ * the keep alive IE.
+ *
+ * @wusbhc shall be referenced and unlocked
+ */
+static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)
+{
+ struct wusb_dev *wusb_dev;
+
+ mutex_lock(&wusbhc->mutex);
+ wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
+ if (wusb_dev == NULL) {
+ dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n",
+ srcaddr);
+ } else {
+ wusb_dev->entry_ts = jiffies;
+ __wusbhc_keep_alive(wusbhc);
+ }
+ mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * Handle a DN_Connect notification (WUSB1.0[7.6.1])
+ *
+ * @wusbhc
+ * @pkt_hdr
+ * @size: Size of the buffer where the notification resides; if the
+ * notification data suggests there should be more data than
+ * available, an error will be signaled and the whole buffer
+ * consumed.
+ *
+ * @wusbhc->mutex shall be held
+ */
+static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
+ struct wusb_dn_hdr *dn_hdr,
+ size_t size)
+{
+ struct device *dev = wusbhc->dev;
+ struct wusb_dn_connect *dnc;
+ char pr_cdid[WUSB_CKHDID_STRSIZE];
+ static const char *beacon_behaviour[] = {
+ "reserved",
+ "self-beacon",
+ "directed-beacon",
+ "no-beacon"
+ };
+
+ if (size < sizeof(*dnc)) {
+ dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n",
+ size, sizeof(*dnc));
+ return;
+ }
+
+ dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr);
+ sprintf(pr_cdid, "%16ph", dnc->CDID.data);
+ dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n",
+ pr_cdid,
+ wusb_dn_connect_prev_dev_addr(dnc),
+ beacon_behaviour[wusb_dn_connect_beacon_behavior(dnc)],
+ wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect");
+ /* ACK the connect */
+ wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid);
+}
+
+/*
+ * Handle a DN_Disconnect notification (WUSB1.0[7.6.1])
+ *
+ * Device is going down -- do the disconnect.
+ *
+ * @wusbhc shall be referenced and unlocked
+ */
+static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)
+{
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+
+ mutex_lock(&wusbhc->mutex);
+ wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
+ if (wusb_dev == NULL) {
+ dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n",
+ srcaddr);
+ } else {
+ dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n",
+ wusb_dev->addr);
+ __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc,
+ wusb_dev->port_idx));
+ }
+ mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * Handle a Device Notification coming a host
+ *
+ * The Device Notification comes from a host (HWA, DWA or WHCI)
+ * wrapped in a set of headers. Somebody else has peeled off those
+ * headers for us and we just get one Device Notifications.
+ *
+ * Invalid DNs (e.g., too short) are discarded.
+ *
+ * @wusbhc shall be referenced
+ *
+ * FIXMES:
+ * - implement priorities as in WUSB1.0[Table 7-55]?
+ */
+void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
+ struct wusb_dn_hdr *dn_hdr, size_t size)
+{
+ struct device *dev = wusbhc->dev;
+
+ if (size < sizeof(struct wusb_dn_hdr)) {
+ dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
+ (int)size, (int)sizeof(struct wusb_dn_hdr));
+ return;
+ }
+ switch (dn_hdr->bType) {
+ case WUSB_DN_CONNECT:
+ wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
+ break;
+ case WUSB_DN_ALIVE:
+ wusbhc_handle_dn_alive(wusbhc, srcaddr);
+ break;
+ case WUSB_DN_DISCONNECT:
+ wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
+ break;
+ case WUSB_DN_MASAVAILCHANGED:
+ case WUSB_DN_RWAKE:
+ case WUSB_DN_SLEEP:
+ /* FIXME: handle these DNs. */
+ break;
+ case WUSB_DN_EPRDY:
+ /* The hardware handles these. */
+ break;
+ default:
+ dev_warn(dev, "unknown DN %u (%d octets) from %u\n",
+ dn_hdr->bType, (int)size, srcaddr);
+ }
+}
+EXPORT_SYMBOL_GPL(wusbhc_handle_dn);
+
+/*
+ * Disconnect a WUSB device from a the cluster
+ *
+ * @wusbhc
+ * @port Fake port where the device is (wusbhc index, not USB port number).
+ *
+ * In Wireless USB, a disconnect is basically telling the device he is
+ * being disconnected and forgetting about him.
+ *
+ * We send the device a Device Disconnect IE (WUSB1.0[7.5.11]) for 100
+ * ms and then keep going.
+ *
+ * We don't do much in case of error; we always pretend we disabled
+ * the port and disconnected the device. If physically the request
+ * didn't get there (many things can fail in the way there), the stack
+ * will reject the device's communication attempts.
+ *
+ * @wusbhc should be refcounted and locked
+ */
+void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx)
+{
+ int result;
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+ struct wuie_disconnect *ie;
+
+ wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
+ if (wusb_dev == NULL) {
+ /* reset no device? ignore */
+ dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n",
+ port_idx);
+ return;
+ }
+ __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
+
+ ie = kzalloc(sizeof(*ie), GFP_KERNEL);
+ if (ie == NULL)
+ return;
+ ie->hdr.bLength = sizeof(*ie);
+ ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT;
+ ie->bDeviceAddress = wusb_dev->addr;
+ result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr);
+ if (result < 0)
+ dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result);
+ else {
+ /* At least 6 MMCs, assuming at least 1 MMC per zone. */
+ msleep(7*4);
+ wusbhc_mmcie_rm(wusbhc, &ie->hdr);
+ }
+ kfree(ie);
+}
+
+/*
+ * Walk over the BOS descriptor, verify and grok it
+ *
+ * @usb_dev: referenced
+ * @wusb_dev: referenced and unlocked
+ *
+ * The BOS descriptor is defined at WUSB1.0[7.4.1], and it defines a
+ * "flexible" way to wrap all kinds of descriptors inside an standard
+ * descriptor (wonder why they didn't use normal descriptors,
+ * btw). Not like they lack code.
+ *
+ * At the end we go to look for the WUSB Device Capabilities
+ * (WUSB1.0[7.4.1.1]) that is wrapped in a device capability descriptor
+ * that is part of the BOS descriptor set. That tells us what does the
+ * device support (dual role, beacon type, UWB PHY rates).
+ */
+static int wusb_dev_bos_grok(struct usb_device *usb_dev,
+ struct wusb_dev *wusb_dev,
+ struct usb_bos_descriptor *bos, size_t desc_size)
+{
+ ssize_t result;
+ struct device *dev = &usb_dev->dev;
+ void *itr, *top;
+
+ /* Walk over BOS capabilities, verify them */
+ itr = (void *)bos + sizeof(*bos);
+ top = itr + desc_size - sizeof(*bos);
+ while (itr < top) {
+ struct usb_dev_cap_header *cap_hdr = itr;
+ size_t cap_size;
+ u8 cap_type;
+ if (top - itr < sizeof(*cap_hdr)) {
+ dev_err(dev, "Device BUG? premature end of BOS header "
+ "data [offset 0x%02x]: only %zu bytes left\n",
+ (int)(itr - (void *)bos), top - itr);
+ result = -ENOSPC;
+ goto error_bad_cap;
+ }
+ cap_size = cap_hdr->bLength;
+ cap_type = cap_hdr->bDevCapabilityType;
+ if (cap_size == 0)
+ break;
+ if (cap_size > top - itr) {
+ dev_err(dev, "Device BUG? premature end of BOS data "
+ "[offset 0x%02x cap %02x %zu bytes]: "
+ "only %zu bytes left\n",
+ (int)(itr - (void *)bos),
+ cap_type, cap_size, top - itr);
+ result = -EBADF;
+ goto error_bad_cap;
+ }
+ switch (cap_type) {
+ case USB_CAP_TYPE_WIRELESS_USB:
+ if (cap_size != sizeof(*wusb_dev->wusb_cap_descr))
+ dev_err(dev, "Device BUG? WUSB Capability "
+ "descriptor is %zu bytes vs %zu "
+ "needed\n", cap_size,
+ sizeof(*wusb_dev->wusb_cap_descr));
+ else
+ wusb_dev->wusb_cap_descr = itr;
+ break;
+ default:
+ dev_err(dev, "BUG? Unknown BOS capability 0x%02x "
+ "(%zu bytes) at offset 0x%02x\n", cap_type,
+ cap_size, (int)(itr - (void *)bos));
+ }
+ itr += cap_size;
+ }
+ result = 0;
+error_bad_cap:
+ return result;
+}
+
+/*
+ * Add information from the BOS descriptors to the device
+ *
+ * @usb_dev: referenced
+ * @wusb_dev: referenced and unlocked
+ *
+ * So what we do is we alloc a space for the BOS descriptor of 64
+ * bytes; read the first four bytes which include the wTotalLength
+ * field (WUSB1.0[T7-26]) and if it fits in those 64 bytes, read the
+ * whole thing. If not we realloc to that size.
+ *
+ * Then we call the groking function, that will fill up
+ * wusb_dev->wusb_cap_descr, which is what we'll need later on.
+ */
+static int wusb_dev_bos_add(struct usb_device *usb_dev,
+ struct wusb_dev *wusb_dev)
+{
+ ssize_t result;
+ struct device *dev = &usb_dev->dev;
+ struct usb_bos_descriptor *bos;
+ size_t alloc_size = 32, desc_size = 4;
+
+ bos = kmalloc(alloc_size, GFP_KERNEL);
+ if (bos == NULL)
+ return -ENOMEM;
+ result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
+ if (result < 4) {
+ dev_err(dev, "Can't get BOS descriptor or too short: %zd\n",
+ result);
+ goto error_get_descriptor;
+ }
+ desc_size = le16_to_cpu(bos->wTotalLength);
+ if (desc_size >= alloc_size) {
+ kfree(bos);
+ alloc_size = desc_size;
+ bos = kmalloc(alloc_size, GFP_KERNEL);
+ if (bos == NULL)
+ return -ENOMEM;
+ }
+ result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
+ if (result < 0 || result != desc_size) {
+ dev_err(dev, "Can't get BOS descriptor or too short (need "
+ "%zu bytes): %zd\n", desc_size, result);
+ goto error_get_descriptor;
+ }
+ if (result < sizeof(*bos)
+ || le16_to_cpu(bos->wTotalLength) != desc_size) {
+ dev_err(dev, "Can't get BOS descriptor or too short (need "
+ "%zu bytes): %zd\n", desc_size, result);
+ goto error_get_descriptor;
+ }
+
+ result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result);
+ if (result < 0)
+ goto error_bad_bos;
+ wusb_dev->bos = bos;
+ return 0;
+
+error_bad_bos:
+error_get_descriptor:
+ kfree(bos);
+ wusb_dev->wusb_cap_descr = NULL;
+ return result;
+}
+
+static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev)
+{
+ kfree(wusb_dev->bos);
+ wusb_dev->wusb_cap_descr = NULL;
+};
+
+/*
+ * USB stack's device addition Notifier Callback
+ *
+ * Called from drivers/usb/core/hub.c when a new device is added; we
+ * use this hook to perform certain WUSB specific setup work on the
+ * new device. As well, it is the first time we can connect the
+ * wusb_dev and the usb_dev. So we note it down in wusb_dev and take a
+ * reference that we'll drop.
+ *
+ * First we need to determine if the device is a WUSB device (else we
+ * ignore it). For that we use the speed setting (USB_SPEED_WIRELESS)
+ * [FIXME: maybe we'd need something more definitive]. If so, we track
+ * it's usb_busd and from there, the WUSB HC.
+ *
+ * Because all WUSB HCs are contained in a 'struct wusbhc', voila, we
+ * get the wusbhc for the device.
+ *
+ * We have a reference on @usb_dev (as we are called at the end of its
+ * enumeration).
+ *
+ * NOTE: @usb_dev locked
+ */
+static void wusb_dev_add_ncb(struct usb_device *usb_dev)
+{
+ int result = 0;
+ struct wusb_dev *wusb_dev;
+ struct wusbhc *wusbhc;
+ struct device *dev = &usb_dev->dev;
+ u8 port_idx;
+
+ if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
+ return; /* skip non wusb and wusb RHs */
+
+ usb_set_device_state(usb_dev, USB_STATE_UNAUTHENTICATED);
+
+ wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+ if (wusbhc == NULL)
+ goto error_nodev;
+ mutex_lock(&wusbhc->mutex);
+ wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
+ port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+ mutex_unlock(&wusbhc->mutex);
+ if (wusb_dev == NULL)
+ goto error_nodev;
+ wusb_dev->usb_dev = usb_get_dev(usb_dev);
+ usb_dev->wusb_dev = wusb_dev_get(wusb_dev);
+ result = wusb_dev_sec_add(wusbhc, usb_dev, wusb_dev);
+ if (result < 0) {
+ dev_err(dev, "Cannot enable security: %d\n", result);
+ goto error_sec_add;
+ }
+ /* Now query the device for it's BOS and attach it to wusb_dev */
+ result = wusb_dev_bos_add(usb_dev, wusb_dev);
+ if (result < 0) {
+ dev_err(dev, "Cannot get BOS descriptors: %d\n", result);
+ goto error_bos_add;
+ }
+ result = wusb_dev_sysfs_add(wusbhc, usb_dev, wusb_dev);
+ if (result < 0)
+ goto error_add_sysfs;
+out:
+ wusb_dev_put(wusb_dev);
+ wusbhc_put(wusbhc);
+error_nodev:
+ return;
+
+error_add_sysfs:
+ wusb_dev_bos_rm(wusb_dev);
+error_bos_add:
+ wusb_dev_sec_rm(wusb_dev);
+error_sec_add:
+ mutex_lock(&wusbhc->mutex);
+ __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
+ mutex_unlock(&wusbhc->mutex);
+ goto out;
+}
+
+/*
+ * Undo all the steps done at connection by the notifier callback
+ *
+ * NOTE: @usb_dev locked
+ */
+static void wusb_dev_rm_ncb(struct usb_device *usb_dev)
+{
+ struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
+
+ if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
+ return; /* skip non wusb and wusb RHs */
+
+ wusb_dev_sysfs_rm(wusb_dev);
+ wusb_dev_bos_rm(wusb_dev);
+ wusb_dev_sec_rm(wusb_dev);
+ wusb_dev->usb_dev = NULL;
+ usb_dev->wusb_dev = NULL;
+ wusb_dev_put(wusb_dev);
+ usb_put_dev(usb_dev);
+}
+
+/*
+ * Handle notifications from the USB stack (notifier call back)
+ *
+ * This is called when the USB stack does a
+ * usb_{bus,device}_{add,remove}() so we can do WUSB specific
+ * handling. It is called with [for the case of
+ * USB_DEVICE_{ADD,REMOVE} with the usb_dev locked.
+ */
+int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
+ void *priv)
+{
+ int result = NOTIFY_OK;
+
+ switch (val) {
+ case USB_DEVICE_ADD:
+ wusb_dev_add_ncb(priv);
+ break;
+ case USB_DEVICE_REMOVE:
+ wusb_dev_rm_ncb(priv);
+ break;
+ case USB_BUS_ADD:
+ /* ignore (for now) */
+ case USB_BUS_REMOVE:
+ break;
+ default:
+ WARN_ON(1);
+ result = NOTIFY_BAD;
+ }
+ return result;
+}
+
+/*
+ * Return a referenced wusb_dev given a @wusbhc and @usb_dev
+ */
+struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *wusbhc,
+ struct usb_device *usb_dev)
+{
+ struct wusb_dev *wusb_dev;
+ u8 port_idx;
+
+ port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+ BUG_ON(port_idx > wusbhc->ports_max);
+ wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
+ if (wusb_dev != NULL) /* ops, device is gone */
+ wusb_dev_get(wusb_dev);
+ return wusb_dev;
+}
+EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev);
+
+void wusb_dev_destroy(struct kref *_wusb_dev)
+{
+ struct wusb_dev *wusb_dev = container_of(_wusb_dev, struct wusb_dev, refcnt);
+
+ list_del_init(&wusb_dev->cack_node);
+ wusb_dev_free(wusb_dev);
+}
+EXPORT_SYMBOL_GPL(wusb_dev_destroy);
+
+/*
+ * Create all the device connect handling infrastructure
+ *
+ * This is basically the device info array, Connect Acknowledgement
+ * (cack) lists, keep-alive timers (and delayed work thread).
+ */
+int wusbhc_devconnect_create(struct wusbhc *wusbhc)
+{
+ wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE;
+ wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr);
+ INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run);
+
+ wusbhc->cack_ie.hdr.bIEIdentifier = WUIE_ID_CONNECTACK;
+ wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr);
+ INIT_LIST_HEAD(&wusbhc->cack_list);
+
+ return 0;
+}
+
+/*
+ * Release all resources taken by the devconnect stuff
+ */
+void wusbhc_devconnect_destroy(struct wusbhc *wusbhc)
+{
+ /* no op */
+}
+
+/*
+ * wusbhc_devconnect_start - start accepting device connections
+ * @wusbhc: the WUSB HC
+ *
+ * Sets the Host Info IE to accept all new connections.
+ *
+ * FIXME: This also enables the keep alives but this is not necessary
+ * until there are connected and authenticated devices.
+ */
+int wusbhc_devconnect_start(struct wusbhc *wusbhc)
+{
+ struct device *dev = wusbhc->dev;
+ struct wuie_host_info *hi;
+ int result;
+
+ hi = kzalloc(sizeof(*hi), GFP_KERNEL);
+ if (hi == NULL)
+ return -ENOMEM;
+
+ hi->hdr.bLength = sizeof(*hi);
+ hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO;
+ hi->attributes = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL);
+ hi->CHID = wusbhc->chid;
+ result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr);
+ if (result < 0) {
+ dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result);
+ goto error_mmcie_set;
+ }
+ wusbhc->wuie_host_info = hi;
+
+ queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+ msecs_to_jiffies(wusbhc->trust_timeout / 2));
+
+ return 0;
+
+error_mmcie_set:
+ kfree(hi);
+ return result;
+}
+
+/*
+ * wusbhc_devconnect_stop - stop managing connected devices
+ * @wusbhc: the WUSB HC
+ *
+ * Disconnects any devices still connected, stops the keep alives and
+ * removes the Host Info IE.
+ */
+void wusbhc_devconnect_stop(struct wusbhc *wusbhc)
+{
+ int i;
+
+ mutex_lock(&wusbhc->mutex);
+ for (i = 0; i < wusbhc->ports_max; i++) {
+ if (wusbhc->port[i].wusb_dev)
+ __wusbhc_dev_disconnect(wusbhc, &wusbhc->port[i]);
+ }
+ mutex_unlock(&wusbhc->mutex);
+
+ cancel_delayed_work_sync(&wusbhc->keep_alive_timer);
+ wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr);
+ kfree(wusbhc->wuie_host_info);
+ wusbhc->wuie_host_info = NULL;
+}
+
+/*
+ * wusb_set_dev_addr - set the WUSB device address used by the host
+ * @wusbhc: the WUSB HC the device is connect to
+ * @wusb_dev: the WUSB device
+ * @addr: new device address
+ */
+int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, u8 addr)
+{
+ int result;
+
+ wusb_dev->addr = addr;
+ result = wusbhc->dev_info_set(wusbhc, wusb_dev);
+ if (result < 0)
+ dev_err(wusbhc->dev, "device %d: failed to set device "
+ "address\n", wusb_dev->port_idx);
+ else
+ dev_info(wusbhc->dev, "device %d: %s addr %u\n",
+ wusb_dev->port_idx,
+ (addr & WUSB_DEV_ADDR_UNAUTH) ? "unauth" : "auth",
+ wusb_dev->addr);
+
+ return result;
+}
diff --git a/drivers/staging/wusbcore/host/Kconfig b/drivers/staging/wusbcore/host/Kconfig
new file mode 100644
index 000000000000..9a73f9360a08
--- /dev/null
+++ b/drivers/staging/wusbcore/host/Kconfig
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config USB_WHCI_HCD
+ tristate "Wireless USB Host Controller Interface (WHCI) driver"
+ depends on USB_PCI && USB && UWB
+ select USB_WUSB
+ select UWB_WHCI
+ help
+ A driver for PCI-based Wireless USB Host Controllers that are
+ compliant with the WHCI specification.
+
+ To compile this driver a module, choose M here: the module
+ will be called "whci-hcd".
+
+config USB_HWA_HCD
+ tristate "Host Wire Adapter (HWA) driver"
+ depends on USB && UWB
+ select USB_WUSB
+ select UWB_HWA
+ help
+ This driver enables you to connect Wireless USB devices to
+ your system using a Host Wire Adaptor USB dongle. This is an
+ UWB Radio Controller and WUSB Host Controller connected to
+ your machine via USB (specified in WUSB1.0).
+
+ To compile this driver a module, choose M here: the module
+ will be called "hwa-hc".
+
diff --git a/drivers/staging/wusbcore/host/Makefile b/drivers/staging/wusbcore/host/Makefile
new file mode 100644
index 000000000000..d65ee8a73e21
--- /dev/null
+++ b/drivers/staging/wusbcore/host/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_USB_WHCI_HCD) += whci/
+obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
diff --git a/drivers/staging/wusbcore/host/hwa-hc.c b/drivers/staging/wusbcore/host/hwa-hc.c
new file mode 100644
index 000000000000..8d959e91fe27
--- /dev/null
+++ b/drivers/staging/wusbcore/host/hwa-hc.c
@@ -0,0 +1,875 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Host Wire Adapter:
+ * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * The HWA driver is a simple layer that forwards requests to the WAHC
+ * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host
+ * Controller) layers.
+ *
+ * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB
+ * Host Controller that is connected to your system via USB (a USB
+ * dongle that implements a USB host...). There is also a Device Wired
+ * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for
+ * transferring data (it is after all a USB host connected via
+ * Wireless USB), we have a common layer called Wire Adapter Host
+ * Controller that does all the hard work. The WUSBHC (Wireless USB
+ * Host Controller) is the part common to WUSB Host Controllers, the
+ * HWA and the PCI-based one, that is implemented following the WHCI
+ * spec. All these layers are implemented in ../wusbcore.
+ *
+ * The main functions are hwahc_op_urb_{en,de}queue(), that pass the
+ * job of converting a URB to a Wire Adapter
+ *
+ * Entry points:
+ *
+ * hwahc_driver_*() Driver initialization, registration and
+ * teardown.
+ *
+ * hwahc_probe() New device came up, create an instance for
+ * it [from device enumeration].
+ *
+ * hwahc_disconnect() Remove device instance [from device
+ * enumeration].
+ *
+ * [__]hwahc_op_*() Host-Wire-Adaptor specific functions for
+ * starting/stopping/etc (some might be made also
+ * DWA).
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include "../wa-hc.h"
+#include "../wusbhc.h"
+
+struct hwahc {
+ struct wusbhc wusbhc; /* has to be 1st */
+ struct wahc wa;
+};
+
+/*
+ * FIXME should be wusbhc
+ *
+ * NOTE: we need to cache the Cluster ID because later...there is no
+ * way to get it :)
+ */
+static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id)
+{
+ int result;
+ struct wusbhc *wusbhc = &hwahc->wusbhc;
+ struct wahc *wa = &hwahc->wa;
+ struct device *dev = &wa->usb_iface->dev;
+
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_CLUSTER_ID,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ cluster_id,
+ wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (result < 0)
+ dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n",
+ cluster_id, result);
+ else
+ wusbhc->cluster_id = cluster_id;
+ dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id);
+ return result;
+}
+
+static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+
+ return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_NUM_DNTS,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ interval << 8 | slots,
+ wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * Reset a WUSB host controller and wait for it to complete doing it.
+ *
+ * @usb_hcd: Pointer to WUSB Host Controller instance.
+ *
+ */
+static int hwahc_op_reset(struct usb_hcd *usb_hcd)
+{
+ int result;
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct device *dev = &hwahc->wa.usb_iface->dev;
+
+ mutex_lock(&wusbhc->mutex);
+ wa_nep_disarm(&hwahc->wa);
+ result = __wa_set_feature(&hwahc->wa, WA_RESET);
+ if (result < 0) {
+ dev_err(dev, "error commanding HC to reset: %d\n", result);
+ goto error_unlock;
+ }
+ result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0);
+ if (result < 0) {
+ dev_err(dev, "error waiting for HC to reset: %d\n", result);
+ goto error_unlock;
+ }
+error_unlock:
+ mutex_unlock(&wusbhc->mutex);
+ return result;
+}
+
+/*
+ * FIXME: break this function up
+ */
+static int hwahc_op_start(struct usb_hcd *usb_hcd)
+{
+ u8 addr;
+ int result;
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ result = -ENOSPC;
+ mutex_lock(&wusbhc->mutex);
+ addr = wusb_cluster_id_get();
+ if (addr == 0)
+ goto error_cluster_id_get;
+ result = __hwahc_set_cluster_id(hwahc, addr);
+ if (result < 0)
+ goto error_set_cluster_id;
+
+ usb_hcd->uses_new_polling = 1;
+ set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
+ usb_hcd->state = HC_STATE_RUNNING;
+
+ /*
+ * prevent USB core from suspending the root hub since
+ * bus_suspend and bus_resume are not yet supported.
+ */
+ pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev);
+
+ result = 0;
+out:
+ mutex_unlock(&wusbhc->mutex);
+ return result;
+
+error_set_cluster_id:
+ wusb_cluster_id_put(addr);
+error_cluster_id_get:
+ goto out;
+
+}
+
+/*
+ * No need to abort pipes, as when this is called, all the children
+ * has been disconnected and that has done it [through
+ * usb_disable_interface() -> usb_disable_endpoint() ->
+ * hwahc_op_ep_disable() - >rpipe_ep_disable()].
+ */
+static void hwahc_op_stop(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+
+ mutex_lock(&wusbhc->mutex);
+ wusb_cluster_id_put(wusbhc->cluster_id);
+ mutex_unlock(&wusbhc->mutex);
+}
+
+static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+
+ /*
+ * We cannot query the HWA for the WUSB time since that requires sending
+ * a synchronous URB and this function can be called in_interrupt.
+ * Instead, query the USB frame number for our parent and use that.
+ */
+ return usb_get_current_frame_number(wa->usb_dev);
+}
+
+static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
+ gfp_t gfp)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp);
+}
+
+static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb,
+ int status)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ return wa_urb_dequeue(&hwahc->wa, urb, status);
+}
+
+/*
+ * Release resources allocated for an endpoint
+ *
+ * If there is an associated rpipe to this endpoint, go ahead and put it.
+ */
+static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ rpipe_ep_disable(&hwahc->wa, ep);
+}
+
+static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
+{
+ int result;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct device *dev = &hwahc->wa.usb_iface->dev;
+
+ result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
+ if (result < 0) {
+ dev_err(dev, "error commanding HC to start: %d\n", result);
+ goto error_stop;
+ }
+ result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
+ if (result < 0) {
+ dev_err(dev, "error waiting for HC to start: %d\n", result);
+ goto error_stop;
+ }
+ result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "cannot listen to notifications: %d\n", result);
+ goto error_stop;
+ }
+ /*
+ * If WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS is set,
+ * disable transfer notifications.
+ */
+ if (hwahc->wa.quirks &
+ WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS) {
+ struct usb_host_interface *cur_altsetting =
+ hwahc->wa.usb_iface->cur_altsetting;
+
+ result = usb_control_msg(hwahc->wa.usb_dev,
+ usb_sndctrlpipe(hwahc->wa.usb_dev, 0),
+ WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE,
+ WA_REQ_ALEREON_FEATURE_SET,
+ cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ /*
+ * If we successfully sent the control message, start DTI here
+ * because no transfer notifications will be received which is
+ * where DTI is normally started.
+ */
+ if (result == 0)
+ result = wa_dti_start(&hwahc->wa);
+ else
+ result = 0; /* OK. Continue normally. */
+
+ if (result < 0) {
+ dev_err(dev, "cannot start DTI: %d\n", result);
+ goto error_dti_start;
+ }
+ }
+
+ return result;
+
+error_dti_start:
+ wa_nep_disarm(&hwahc->wa);
+error_stop:
+ __wa_clear_feature(&hwahc->wa, WA_ENABLE);
+ return result;
+}
+
+static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ int ret;
+
+ ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_CHAN_STOP,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ delay * 1000,
+ iface_no,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (ret == 0)
+ msleep(delay);
+
+ wa_nep_disarm(&hwahc->wa);
+ __wa_stop(&hwahc->wa);
+}
+
+/*
+ * Set the UWB MAS allocation for the WUSB cluster
+ *
+ * @stream_index: stream to use (-1 for cancelling the allocation)
+ * @mas: mas bitmap to use
+ */
+static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index,
+ const struct uwb_mas_bm *mas)
+{
+ int result;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ struct device *dev = &wa->usb_iface->dev;
+ u8 mas_le[UWB_NUM_MAS/8];
+
+ /* Set the stream index */
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_STREAM_IDX,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ stream_index,
+ wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "Cannot set WUSB stream index: %d\n", result);
+ goto out;
+ }
+ uwb_mas_bm_copy_le(mas_le, mas);
+ /* Set the MAS allocation */
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_WUSB_MAS,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ mas_le, 32, USB_CTRL_SET_TIMEOUT);
+ if (result < 0)
+ dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result);
+out:
+ return result;
+}
+
+/*
+ * Add an IE to the host's MMC
+ *
+ * @interval: See WUSB1.0[8.5.3.1]
+ * @repeat_cnt: See WUSB1.0[8.5.3.1]
+ * @handle: See WUSB1.0[8.5.3.1]
+ * @wuie: Pointer to the header of the WUSB IE data to add.
+ * MUST BE allocated in a kmalloc buffer (no stack or
+ * vmalloc).
+ *
+ * NOTE: the format of the WUSB IEs for MMCs are different to the
+ * normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length +
+ * Id in WUSB IEs). Standards...you gotta love'em.
+ */
+static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval,
+ u8 repeat_cnt, u8 handle,
+ struct wuie_hdr *wuie)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+
+ return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_ADD_MMC_IE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ interval << 8 | repeat_cnt,
+ handle << 8 | iface_no,
+ wuie, wuie->bLength, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * Remove an IE to the host's MMC
+ *
+ * @handle: See WUSB1.0[8.5.3.1]
+ */
+static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_REMOVE_MMC_IE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, handle << 8 | iface_no,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * Update device information for a given fake port
+ *
+ * @port_idx: Fake port to which device is connected (wusbhc index, not
+ * USB port number).
+ */
+static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc,
+ struct wusb_dev *wusb_dev)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ struct hwa_dev_info *dev_info;
+ int ret;
+
+ /* fill out the Device Info buffer and send it */
+ dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL);
+ if (!dev_info)
+ return -ENOMEM;
+ uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability,
+ &wusb_dev->availability);
+ dev_info->bDeviceAddress = wusb_dev->addr;
+
+ /*
+ * If the descriptors haven't been read yet, use a default PHY
+ * rate of 53.3 Mbit/s only. The correct value will be used
+ * when this will be called again as part of the
+ * authentication process (which occurs after the descriptors
+ * have been read).
+ */
+ if (wusb_dev->wusb_cap_descr)
+ dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates;
+ else
+ dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53);
+
+ ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_DEV_INFO,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, wusb_dev->port_idx << 8 | iface_no,
+ dev_info, sizeof(struct hwa_dev_info),
+ USB_CTRL_SET_TIMEOUT);
+ kfree(dev_info);
+ return ret;
+}
+
+/*
+ * Set host's idea of which encryption (and key) method to use when
+ * talking to ad evice on a given port.
+ *
+ * If key is NULL, it means disable encryption for that "virtual port"
+ * (used when we disconnect).
+ */
+static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+ const void *key, size_t key_size,
+ u8 key_idx)
+{
+ int result = -ENOMEM;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ struct usb_key_descriptor *keyd;
+ size_t keyd_len;
+
+ keyd_len = sizeof(*keyd) + key_size;
+ keyd = kzalloc(keyd_len, GFP_KERNEL);
+ if (keyd == NULL)
+ return -ENOMEM;
+
+ keyd->bLength = keyd_len;
+ keyd->bDescriptorType = USB_DT_KEY;
+ keyd->tTKID[0] = (tkid >> 0) & 0xff;
+ keyd->tTKID[1] = (tkid >> 8) & 0xff;
+ keyd->tTKID[2] = (tkid >> 16) & 0xff;
+ memcpy(keyd->bKeyData, key, key_size);
+
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_SET_DESCRIPTOR,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ USB_DT_KEY << 8 | key_idx,
+ port_idx << 8 | iface_no,
+ keyd, keyd_len, USB_CTRL_SET_TIMEOUT);
+
+ kzfree(keyd); /* clear keys etc. */
+ return result;
+}
+
+/*
+ * Set host's idea of which encryption (and key) method to use when
+ * talking to ad evice on a given port.
+ *
+ * If key is NULL, it means disable encryption for that "virtual port"
+ * (used when we disconnect).
+ */
+static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+ const void *key, size_t key_size)
+{
+ int result = -ENOMEM;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ u8 encryption_value;
+
+ /* Tell the host which key to use to talk to the device */
+ if (key) {
+ u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK,
+ WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+ result = __hwahc_dev_set_key(wusbhc, port_idx, tkid,
+ key, key_size, key_idx);
+ if (result < 0)
+ goto error_set_key;
+ encryption_value = wusbhc->ccm1_etd->bEncryptionValue;
+ } else {
+ /* FIXME: this should come from wusbhc->etd[UNSECURE].value */
+ encryption_value = 0;
+ }
+
+ /* Set the encryption type for communicating with the device */
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_SET_ENCRYPTION,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ encryption_value, port_idx << 8 | iface_no,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (result < 0)
+ dev_err(wusbhc->dev, "Can't set host's WUSB encryption for "
+ "port index %u to %s (value %d): %d\n", port_idx,
+ wusb_et_name(wusbhc->ccm1_etd->bEncryptionType),
+ wusbhc->ccm1_etd->bEncryptionValue, result);
+error_set_key:
+ return result;
+}
+
+/*
+ * Set host's GTK key
+ */
+static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+ const void *key, size_t key_size)
+{
+ u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK,
+ WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+ return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx);
+}
+
+/*
+ * Get the Wire Adapter class-specific descriptor
+ *
+ * NOTE: this descriptor comes with the big bundled configuration
+ * descriptor that includes the interfaces' and endpoints', so
+ * we just look for it in the cached copy kept by the USB stack.
+ *
+ * NOTE2: We convert LE fields to CPU order.
+ */
+static int wa_fill_descr(struct wahc *wa)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+ char *itr;
+ struct usb_device *usb_dev = wa->usb_dev;
+ struct usb_descriptor_header *hdr;
+ struct usb_wa_descriptor *wa_descr;
+ size_t itr_size, actconfig_idx;
+
+ actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
+ sizeof(usb_dev->config[0]);
+ itr = usb_dev->rawdescriptors[actconfig_idx];
+ itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+ while (itr_size >= sizeof(*hdr)) {
+ hdr = (struct usb_descriptor_header *) itr;
+ dev_dbg(dev, "Extra device descriptor: "
+ "type %02x/%u bytes @ %zu (%zu left)\n",
+ hdr->bDescriptorType, hdr->bLength,
+ (itr - usb_dev->rawdescriptors[actconfig_idx]),
+ itr_size);
+ if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER)
+ goto found;
+ itr += hdr->bLength;
+ itr_size -= hdr->bLength;
+ }
+ dev_err(dev, "cannot find Wire Adapter Class descriptor\n");
+ return -ENODEV;
+
+found:
+ result = -EINVAL;
+ if (hdr->bLength > itr_size) { /* is it available? */
+ dev_err(dev, "incomplete Wire Adapter Class descriptor "
+ "(%zu bytes left, %u needed)\n",
+ itr_size, hdr->bLength);
+ goto error;
+ }
+ if (hdr->bLength < sizeof(*wa->wa_descr)) {
+ dev_err(dev, "short Wire Adapter Class descriptor\n");
+ goto error;
+ }
+ wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr;
+ if (le16_to_cpu(wa_descr->bcdWAVersion) > 0x0100)
+ dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n",
+ (le16_to_cpu(wa_descr->bcdWAVersion) & 0xff00) >> 8,
+ le16_to_cpu(wa_descr->bcdWAVersion) & 0x00ff);
+ result = 0;
+error:
+ return result;
+}
+
+static const struct hc_driver hwahc_hc_driver = {
+ .description = "hwa-hcd",
+ .product_desc = "Wireless USB HWA host controller",
+ .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd),
+ .irq = NULL, /* FIXME */
+ .flags = HCD_USB25,
+ .reset = hwahc_op_reset,
+ .start = hwahc_op_start,
+ .stop = hwahc_op_stop,
+ .get_frame_number = hwahc_op_get_frame_number,
+ .urb_enqueue = hwahc_op_urb_enqueue,
+ .urb_dequeue = hwahc_op_urb_dequeue,
+ .endpoint_disable = hwahc_op_endpoint_disable,
+
+ .hub_status_data = wusbhc_rh_status_data,
+ .hub_control = wusbhc_rh_control,
+ .start_port_reset = wusbhc_rh_start_port_reset,
+};
+
+static int hwahc_security_create(struct hwahc *hwahc)
+{
+ int result;
+ struct wusbhc *wusbhc = &hwahc->wusbhc;
+ struct usb_device *usb_dev = hwahc->wa.usb_dev;
+ struct device *dev = &usb_dev->dev;
+ struct usb_security_descriptor *secd;
+ struct usb_encryption_descriptor *etd;
+ void *itr, *top;
+ size_t itr_size, needed, bytes;
+ u8 index;
+ char buf[64];
+
+ /* Find the host's security descriptors in the config descr bundle */
+ index = (usb_dev->actconfig - usb_dev->config) /
+ sizeof(usb_dev->config[0]);
+ itr = usb_dev->rawdescriptors[index];
+ itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+ top = itr + itr_size;
+ result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
+ le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
+ USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
+ if (result == -1) {
+ dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
+ return 0;
+ }
+ needed = sizeof(*secd);
+ if (top - (void *)secd < needed) {
+ dev_err(dev, "BUG? Not enough data to process security "
+ "descriptor header (%zu bytes left vs %zu needed)\n",
+ top - (void *) secd, needed);
+ return 0;
+ }
+ needed = le16_to_cpu(secd->wTotalLength);
+ if (top - (void *)secd < needed) {
+ dev_err(dev, "BUG? Not enough data to process security "
+ "descriptors (%zu bytes left vs %zu needed)\n",
+ top - (void *) secd, needed);
+ return 0;
+ }
+ /* Walk over the sec descriptors and store CCM1's on wusbhc */
+ itr = (void *) secd + sizeof(*secd);
+ top = (void *) secd + le16_to_cpu(secd->wTotalLength);
+ index = 0;
+ bytes = 0;
+ while (itr < top) {
+ etd = itr;
+ if (top - itr < sizeof(*etd)) {
+ dev_err(dev, "BUG: bad host security descriptor; "
+ "not enough data (%zu vs %zu left)\n",
+ top - itr, sizeof(*etd));
+ break;
+ }
+ if (etd->bLength < sizeof(*etd)) {
+ dev_err(dev, "BUG: bad host encryption descriptor; "
+ "descriptor is too short "
+ "(%zu vs %zu needed)\n",
+ (size_t)etd->bLength, sizeof(*etd));
+ break;
+ }
+ itr += etd->bLength;
+ bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
+ "%s (0x%02x) ",
+ wusb_et_name(etd->bEncryptionType),
+ etd->bEncryptionValue);
+ wusbhc->ccm1_etd = etd;
+ }
+ dev_info(dev, "supported encryption types: %s\n", buf);
+ if (wusbhc->ccm1_etd == NULL) {
+ dev_err(dev, "E: host doesn't support CCM-1 crypto\n");
+ return 0;
+ }
+ /* Pretty print what we support */
+ return 0;
+}
+
+static void hwahc_security_release(struct hwahc *hwahc)
+{
+ /* nothing to do here so far... */
+}
+
+static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface,
+ kernel_ulong_t quirks)
+{
+ int result;
+ struct device *dev = &iface->dev;
+ struct wusbhc *wusbhc = &hwahc->wusbhc;
+ struct wahc *wa = &hwahc->wa;
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+
+ wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */
+ wa->usb_iface = usb_get_intf(iface);
+ wusbhc->dev = dev;
+ /* defer getting the uwb_rc handle until it is needed since it
+ * may not have been registered by the hwa_rc driver yet. */
+ wusbhc->uwb_rc = NULL;
+ result = wa_fill_descr(wa); /* Get the device descriptor */
+ if (result < 0)
+ goto error_fill_descriptor;
+ if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) {
+ dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB "
+ "adapter (%u ports)\n", wa->wa_descr->bNumPorts);
+ wusbhc->ports_max = USB_MAXCHILDREN;
+ } else {
+ wusbhc->ports_max = wa->wa_descr->bNumPorts;
+ }
+ wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs;
+ wusbhc->start = __hwahc_op_wusbhc_start;
+ wusbhc->stop = __hwahc_op_wusbhc_stop;
+ wusbhc->mmcie_add = __hwahc_op_mmcie_add;
+ wusbhc->mmcie_rm = __hwahc_op_mmcie_rm;
+ wusbhc->dev_info_set = __hwahc_op_dev_info_set;
+ wusbhc->bwa_set = __hwahc_op_bwa_set;
+ wusbhc->set_num_dnts = __hwahc_op_set_num_dnts;
+ wusbhc->set_ptk = __hwahc_op_set_ptk;
+ wusbhc->set_gtk = __hwahc_op_set_gtk;
+ result = hwahc_security_create(hwahc);
+ if (result < 0) {
+ dev_err(dev, "Can't initialize security: %d\n", result);
+ goto error_security_create;
+ }
+ wa->wusb = wusbhc; /* FIXME: ugly, need to fix */
+ result = wusbhc_create(&hwahc->wusbhc);
+ if (result < 0) {
+ dev_err(dev, "Can't create WUSB HC structures: %d\n", result);
+ goto error_wusbhc_create;
+ }
+ result = wa_create(&hwahc->wa, iface, quirks);
+ if (result < 0)
+ goto error_wa_create;
+ return 0;
+
+error_wa_create:
+ wusbhc_destroy(&hwahc->wusbhc);
+error_wusbhc_create:
+ /* WA Descr fill allocs no resources */
+error_security_create:
+error_fill_descriptor:
+ usb_put_intf(iface);
+ usb_put_dev(usb_dev);
+ return result;
+}
+
+static void hwahc_destroy(struct hwahc *hwahc)
+{
+ struct wusbhc *wusbhc = &hwahc->wusbhc;
+
+ mutex_lock(&wusbhc->mutex);
+ __wa_destroy(&hwahc->wa);
+ wusbhc_destroy(&hwahc->wusbhc);
+ hwahc_security_release(hwahc);
+ hwahc->wusbhc.dev = NULL;
+ uwb_rc_put(wusbhc->uwb_rc);
+ usb_put_intf(hwahc->wa.usb_iface);
+ usb_put_dev(hwahc->wa.usb_dev);
+ mutex_unlock(&wusbhc->mutex);
+}
+
+static void hwahc_init(struct hwahc *hwahc)
+{
+ wa_init(&hwahc->wa);
+}
+
+static int hwahc_probe(struct usb_interface *usb_iface,
+ const struct usb_device_id *id)
+{
+ int result;
+ struct usb_hcd *usb_hcd;
+ struct wusbhc *wusbhc;
+ struct hwahc *hwahc;
+ struct device *dev = &usb_iface->dev;
+
+ result = -ENOMEM;
+ usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa");
+ if (usb_hcd == NULL) {
+ dev_err(dev, "unable to allocate instance\n");
+ goto error_alloc;
+ }
+ usb_hcd->wireless = 1;
+ usb_hcd->self.sg_tablesize = ~0;
+ wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ hwahc_init(hwahc);
+ result = hwahc_create(hwahc, usb_iface, id->driver_info);
+ if (result < 0) {
+ dev_err(dev, "Cannot initialize internals: %d\n", result);
+ goto error_hwahc_create;
+ }
+ result = usb_add_hcd(usb_hcd, 0, 0);
+ if (result < 0) {
+ dev_err(dev, "Cannot add HCD: %d\n", result);
+ goto error_add_hcd;
+ }
+ device_wakeup_enable(usb_hcd->self.controller);
+ result = wusbhc_b_create(&hwahc->wusbhc);
+ if (result < 0) {
+ dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result);
+ goto error_wusbhc_b_create;
+ }
+ return 0;
+
+error_wusbhc_b_create:
+ usb_remove_hcd(usb_hcd);
+error_add_hcd:
+ hwahc_destroy(hwahc);
+error_hwahc_create:
+ usb_put_hcd(usb_hcd);
+error_alloc:
+ return result;
+}
+
+static void hwahc_disconnect(struct usb_interface *usb_iface)
+{
+ struct usb_hcd *usb_hcd;
+ struct wusbhc *wusbhc;
+ struct hwahc *hwahc;
+
+ usb_hcd = usb_get_intfdata(usb_iface);
+ wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ wusbhc_b_destroy(&hwahc->wusbhc);
+ usb_remove_hcd(usb_hcd);
+ hwahc_destroy(hwahc);
+ usb_put_hcd(usb_hcd);
+}
+
+static const struct usb_device_id hwahc_id_table[] = {
+ /* Alereon 5310 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01),
+ .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
+ WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
+ /* Alereon 5611 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01),
+ .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
+ WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
+ /* FIXME: use class labels for this */
+ { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },
+ {},
+};
+MODULE_DEVICE_TABLE(usb, hwahc_id_table);
+
+static struct usb_driver hwahc_driver = {
+ .name = "hwa-hc",
+ .probe = hwahc_probe,
+ .disconnect = hwahc_disconnect,
+ .id_table = hwahc_id_table,
+};
+
+module_usb_driver(hwahc_driver);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/host/whci/Makefile b/drivers/staging/wusbcore/host/whci/Makefile
new file mode 100644
index 000000000000..859d20079df6
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o
+
+whci-hcd-y := \
+ asl.o \
+ debug.o \
+ hcd.o \
+ hw.o \
+ init.o \
+ int.o \
+ pzl.o \
+ qset.o \
+ wusb.o
diff --git a/drivers/staging/wusbcore/host/whci/asl.c b/drivers/staging/wusbcore/host/whci/asl.c
new file mode 100644
index 000000000000..a2b9a50cfb80
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/asl.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) asynchronous schedule management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset,
+ struct whc_qset **next, struct whc_qset **prev)
+{
+ struct list_head *n, *p;
+
+ BUG_ON(list_empty(&whc->async_list));
+
+ n = qset->list_node.next;
+ if (n == &whc->async_list)
+ n = n->next;
+ p = qset->list_node.prev;
+ if (p == &whc->async_list)
+ p = p->prev;
+
+ *next = container_of(n, struct whc_qset, list_node);
+ *prev = container_of(p, struct whc_qset, list_node);
+
+}
+
+static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset)
+{
+ list_move(&qset->list_node, &whc->async_list);
+ qset->in_sw_list = true;
+}
+
+static void asl_qset_insert(struct whc *whc, struct whc_qset *qset)
+{
+ struct whc_qset *next, *prev;
+
+ qset_clear(whc, qset);
+
+ /* Link into ASL. */
+ qset_get_next_prev(whc, qset, &next, &prev);
+ whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma);
+ whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma);
+ qset->in_hw_list = true;
+}
+
+static void asl_qset_remove(struct whc *whc, struct whc_qset *qset)
+{
+ struct whc_qset *prev, *next;
+
+ qset_get_next_prev(whc, qset, &next, &prev);
+
+ list_move(&qset->list_node, &whc->async_removed_list);
+ qset->in_sw_list = false;
+
+ /*
+ * No more qsets in the ASL? The caller must stop the ASL as
+ * it's no longer valid.
+ */
+ if (list_empty(&whc->async_list))
+ return;
+
+ /* Remove from ASL. */
+ whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma);
+ qset->in_hw_list = false;
+}
+
+/**
+ * process_qset - process any recently inactivated or halted qTDs in a
+ * qset.
+ *
+ * After inactive qTDs are removed, new qTDs can be added if the
+ * urb queue still contains URBs.
+ *
+ * Returns any additional WUSBCMD bits for the ASL sync command (i.e.,
+ * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed).
+ */
+static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
+{
+ enum whc_update update = 0;
+ uint32_t status = 0;
+
+ while (qset->ntds) {
+ struct whc_qtd *td;
+
+ td = &qset->qtd[qset->td_start];
+ status = le32_to_cpu(td->status);
+
+ /*
+ * Nothing to do with a still active qTD.
+ */
+ if (status & QTD_STS_ACTIVE)
+ break;
+
+ if (status & QTD_STS_HALTED) {
+ /* Ug, an error. */
+ process_halted_qtd(whc, qset, td);
+ /* A halted qTD always triggers an update
+ because the qset was either removed or
+ reactivated. */
+ update |= WHC_UPDATE_UPDATED;
+ goto done;
+ }
+
+ /* Mmm, a completed qTD. */
+ process_inactive_qtd(whc, qset, td);
+ }
+
+ if (!qset->remove)
+ update |= qset_add_qtds(whc, qset);
+
+done:
+ /*
+ * Remove this qset from the ASL if requested, but only if has
+ * no qTDs.
+ */
+ if (qset->remove && qset->ntds == 0) {
+ asl_qset_remove(whc, qset);
+ update |= WHC_UPDATE_REMOVED;
+ }
+ return update;
+}
+
+void asl_start(struct whc *whc)
+{
+ struct whc_qset *qset;
+
+ qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
+
+ le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR);
+
+ whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED,
+ 1000, "start ASL");
+}
+
+void asl_stop(struct whc *whc)
+{
+ whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_ASYNC_SCHED, 0,
+ 1000, "stop ASL");
+}
+
+/**
+ * asl_update - request an ASL update and wait for the hardware to be synced
+ * @whc: the WHCI HC
+ * @wusbcmd: WUSBCMD value to start the update.
+ *
+ * If the WUSB HC is inactive (i.e., the ASL is stopped) then the
+ * update must be skipped as the hardware may not respond to update
+ * requests.
+ */
+void asl_update(struct whc *whc, uint32_t wusbcmd)
+{
+ struct wusbhc *wusbhc = &whc->wusbhc;
+ long t;
+
+ mutex_lock(&wusbhc->mutex);
+ if (wusbhc->active) {
+ whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
+ t = wait_event_timeout(
+ whc->async_list_wq,
+ (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0,
+ msecs_to_jiffies(1000));
+ if (t == 0)
+ whc_hw_error(whc, "ASL update timeout");
+ }
+ mutex_unlock(&wusbhc->mutex);
+}
+
+/**
+ * scan_async_work - scan the ASL for qsets to process.
+ *
+ * Process each qset in the ASL in turn and then signal the WHC that
+ * the ASL has been updated.
+ *
+ * Then start, stop or update the asynchronous schedule as required.
+ */
+void scan_async_work(struct work_struct *work)
+{
+ struct whc *whc = container_of(work, struct whc, async_work);
+ struct whc_qset *qset, *t;
+ enum whc_update update = 0;
+
+ spin_lock_irq(&whc->lock);
+
+ /*
+ * Transerve the software list backwards so new qsets can be
+ * safely inserted into the ASL without making it non-circular.
+ */
+ list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) {
+ if (!qset->in_hw_list) {
+ asl_qset_insert(whc, qset);
+ update |= WHC_UPDATE_ADDED;
+ }
+
+ update |= process_qset(whc, qset);
+ }
+
+ spin_unlock_irq(&whc->lock);
+
+ if (update) {
+ uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB;
+ if (update & WHC_UPDATE_REMOVED)
+ wusbcmd |= WUSBCMD_ASYNC_QSET_RM;
+ asl_update(whc, wusbcmd);
+ }
+
+ /*
+ * Now that the ASL is updated, complete the removal of any
+ * removed qsets.
+ *
+ * If the qset was to be reset, do so and reinsert it into the
+ * ASL if it has pending transfers.
+ */
+ spin_lock_irq(&whc->lock);
+
+ list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
+ qset_remove_complete(whc, qset);
+ if (qset->reset) {
+ qset_reset(whc, qset);
+ if (!list_empty(&qset->stds)) {
+ asl_qset_insert_begin(whc, qset);
+ queue_work(whc->workqueue, &whc->async_work);
+ }
+ }
+ }
+
+ spin_unlock_irq(&whc->lock);
+}
+
+/**
+ * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL).
+ * @whc: the WHCI host controller
+ * @urb: the URB to enqueue
+ * @mem_flags: flags for any memory allocations
+ *
+ * The qset for the endpoint is obtained and the urb queued on to it.
+ *
+ * Work is scheduled to update the hardware's view of the ASL.
+ */
+int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
+{
+ struct whc_qset *qset;
+ int err;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
+ if (err < 0) {
+ spin_unlock_irqrestore(&whc->lock, flags);
+ return err;
+ }
+
+ qset = get_qset(whc, urb, GFP_ATOMIC);
+ if (qset == NULL)
+ err = -ENOMEM;
+ else
+ err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+ if (!err) {
+ if (!qset->in_sw_list && !qset->remove)
+ asl_qset_insert_begin(whc, qset);
+ } else
+ usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ if (!err)
+ queue_work(whc->workqueue, &whc->async_work);
+
+ return err;
+}
+
+/**
+ * asl_urb_dequeue - remove an URB (qset) from the async list.
+ * @whc: the WHCI host controller
+ * @urb: the URB to dequeue
+ * @status: the current status of the URB
+ *
+ * URBs that do yet have qTDs can simply be removed from the software
+ * queue, otherwise the qset must be removed from the ASL so the qTDs
+ * can be removed.
+ */
+int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
+{
+ struct whc_urb *wurb = urb->hcpriv;
+ struct whc_qset *qset = wurb->qset;
+ struct whc_std *std, *t;
+ bool has_qtd = false;
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
+ if (ret < 0)
+ goto out;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+ if (std->urb == urb) {
+ if (std->qtd)
+ has_qtd = true;
+ qset_free_std(whc, std);
+ } else
+ std->qtd = NULL; /* so this std is re-added when the qset is */
+ }
+
+ if (has_qtd) {
+ asl_qset_remove(whc, qset);
+ wurb->status = status;
+ wurb->is_async = true;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+ } else
+ qset_remove_urb(whc, qset, urb, status);
+out:
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ return ret;
+}
+
+/**
+ * asl_qset_delete - delete a qset from the ASL
+ */
+void asl_qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+ qset->remove = 1;
+ queue_work(whc->workqueue, &whc->async_work);
+ qset_delete(whc, qset);
+}
+
+/**
+ * asl_init - initialize the asynchronous schedule list
+ *
+ * A dummy qset with no qTDs is added to the ASL to simplify removing
+ * qsets (no need to stop the ASL when the last qset is removed).
+ */
+int asl_init(struct whc *whc)
+{
+ struct whc_qset *qset;
+
+ qset = qset_alloc(whc, GFP_KERNEL);
+ if (qset == NULL)
+ return -ENOMEM;
+
+ asl_qset_insert_begin(whc, qset);
+ asl_qset_insert(whc, qset);
+
+ return 0;
+}
+
+/**
+ * asl_clean_up - free ASL resources
+ *
+ * The ASL is stopped and empty except for the dummy qset.
+ */
+void asl_clean_up(struct whc *whc)
+{
+ struct whc_qset *qset;
+
+ if (!list_empty(&whc->async_list)) {
+ qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
+ list_del(&qset->list_node);
+ qset_free(whc, qset);
+ }
+}
diff --git a/drivers/staging/wusbcore/host/whci/debug.c b/drivers/staging/wusbcore/host/whci/debug.c
new file mode 100644
index 000000000000..443da6719147
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/debug.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) debug.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/export.h>
+
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+struct whc_dbg {
+ struct dentry *di_f;
+ struct dentry *asl_f;
+ struct dentry *pzl_f;
+};
+
+static void qset_print(struct seq_file *s, struct whc_qset *qset)
+{
+ static const char *qh_type[] = {
+ "ctrl", "isoc", "bulk", "intr", "rsvd", "rsvd", "rsvd", "lpintr", };
+ struct whc_std *std;
+ struct urb *urb = NULL;
+ int i;
+
+ seq_printf(s, "qset %08x", (u32)qset->qset_dma);
+ if (&qset->list_node == qset->whc->async_list.prev) {
+ seq_printf(s, " (dummy)\n");
+ } else {
+ seq_printf(s, " ep%d%s-%s maxpkt: %d\n",
+ qset->qh.info1 & 0x0f,
+ (qset->qh.info1 >> 4) & 0x1 ? "in" : "out",
+ qh_type[(qset->qh.info1 >> 5) & 0x7],
+ (qset->qh.info1 >> 16) & 0xffff);
+ }
+ seq_printf(s, " -> %08x\n", (u32)qset->qh.link);
+ seq_printf(s, " info: %08x %08x %08x\n",
+ qset->qh.info1, qset->qh.info2, qset->qh.info3);
+ seq_printf(s, " sts: %04x errs: %d curwin: %08x\n",
+ qset->qh.status, qset->qh.err_count, qset->qh.cur_window);
+ seq_printf(s, " TD: sts: %08x opts: %08x\n",
+ qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
+
+ for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
+ seq_printf(s, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
+ i == qset->td_start ? 'S' : ' ',
+ i == qset->td_end ? 'E' : ' ',
+ i, qset->qtd[i].status, qset->qtd[i].options,
+ (u32)qset->qtd[i].page_list_ptr);
+ }
+ seq_printf(s, " ntds: %d\n", qset->ntds);
+ list_for_each_entry(std, &qset->stds, list_node) {
+ if (urb != std->urb) {
+ urb = std->urb;
+ seq_printf(s, " urb %p transferred: %d bytes\n", urb,
+ urb->actual_length);
+ }
+ if (std->qtd)
+ seq_printf(s, " sTD[%td]: %zu bytes @ %08x\n",
+ std->qtd - &qset->qtd[0],
+ std->len, std->num_pointers ?
+ (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
+ else
+ seq_printf(s, " sTD[-]: %zd bytes @ %08x\n",
+ std->len, std->num_pointers ?
+ (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
+ }
+}
+
+static int di_show(struct seq_file *s, void *p)
+{
+ struct whc *whc = s->private;
+ int d;
+
+ for (d = 0; d < whc->n_devices; d++) {
+ struct di_buf_entry *di = &whc->di_buf[d];
+
+ seq_printf(s, "DI[%d]\n", d);
+ seq_printf(s, " availability: %*pb\n",
+ UWB_NUM_MAS, (unsigned long *)di->availability_info);
+ seq_printf(s, " %c%c key idx: %d dev addr: %d\n",
+ (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
+ (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
+ (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
+ (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
+ }
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(di);
+
+static int asl_show(struct seq_file *s, void *p)
+{
+ struct whc *whc = s->private;
+ struct whc_qset *qset;
+
+ list_for_each_entry(qset, &whc->async_list, list_node) {
+ qset_print(s, qset);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(asl);
+
+static int pzl_show(struct seq_file *s, void *p)
+{
+ struct whc *whc = s->private;
+ struct whc_qset *qset;
+ int period;
+
+ for (period = 0; period < 5; period++) {
+ seq_printf(s, "Period %d\n", period);
+ list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
+ qset_print(s, qset);
+ }
+ }
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pzl);
+
+void whc_dbg_init(struct whc *whc)
+{
+ if (whc->wusbhc.pal.debugfs_dir == NULL)
+ return;
+
+ whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL);
+ if (whc->dbg == NULL)
+ return;
+
+ whc->dbg->di_f = debugfs_create_file("di", 0444,
+ whc->wusbhc.pal.debugfs_dir, whc,
+ &di_fops);
+ whc->dbg->asl_f = debugfs_create_file("asl", 0444,
+ whc->wusbhc.pal.debugfs_dir, whc,
+ &asl_fops);
+ whc->dbg->pzl_f = debugfs_create_file("pzl", 0444,
+ whc->wusbhc.pal.debugfs_dir, whc,
+ &pzl_fops);
+}
+
+void whc_dbg_clean_up(struct whc *whc)
+{
+ if (whc->dbg) {
+ debugfs_remove(whc->dbg->pzl_f);
+ debugfs_remove(whc->dbg->asl_f);
+ debugfs_remove(whc->dbg->di_f);
+ kfree(whc->dbg);
+ }
+}
diff --git a/drivers/staging/wusbcore/host/whci/hcd.c b/drivers/staging/wusbcore/host/whci/hcd.c
new file mode 100644
index 000000000000..bee1ff2d35be
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/hcd.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) driver.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+/*
+ * One time initialization.
+ *
+ * Nothing to do here.
+ */
+static int whc_reset(struct usb_hcd *usb_hcd)
+{
+ return 0;
+}
+
+/*
+ * Start the wireless host controller.
+ *
+ * Start device notification.
+ *
+ * Put hc into run state, set DNTS parameters.
+ */
+static int whc_start(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u8 bcid;
+ int ret;
+
+ mutex_lock(&wusbhc->mutex);
+
+ le_writel(WUSBINTR_GEN_CMD_DONE
+ | WUSBINTR_HOST_ERR
+ | WUSBINTR_ASYNC_SCHED_SYNCED
+ | WUSBINTR_DNTS_INT
+ | WUSBINTR_ERR_INT
+ | WUSBINTR_INT,
+ whc->base + WUSBINTR);
+
+ /* set cluster ID */
+ bcid = wusb_cluster_id_get();
+ ret = whc_set_cluster_id(whc, bcid);
+ if (ret < 0)
+ goto out;
+ wusbhc->cluster_id = bcid;
+
+ /* start HC */
+ whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
+
+ usb_hcd->uses_new_polling = 1;
+ set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
+ usb_hcd->state = HC_STATE_RUNNING;
+
+out:
+ mutex_unlock(&wusbhc->mutex);
+ return ret;
+}
+
+
+/*
+ * Stop the wireless host controller.
+ *
+ * Stop device notification.
+ *
+ * Wait for pending transfer to stop? Put hc into stop state?
+ */
+static void whc_stop(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ mutex_lock(&wusbhc->mutex);
+
+ /* stop HC */
+ le_writel(0, whc->base + WUSBINTR);
+ whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_HCHALTED, WUSBSTS_HCHALTED,
+ 100, "HC to halt");
+
+ wusb_cluster_id_put(wusbhc->cluster_id);
+
+ mutex_unlock(&wusbhc->mutex);
+}
+
+static int whc_get_frame_number(struct usb_hcd *usb_hcd)
+{
+ /* Frame numbers are not applicable to WUSB. */
+ return -ENOSYS;
+}
+
+
+/*
+ * Queue an URB to the ASL or PZL
+ */
+static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ int ret;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_INTERRUPT:
+ ret = pzl_urb_enqueue(whc, urb, mem_flags);
+ break;
+ case PIPE_ISOCHRONOUS:
+ dev_err(&whc->umc->dev, "isochronous transfers unsupported\n");
+ ret = -ENOTSUPP;
+ break;
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ default:
+ ret = asl_urb_enqueue(whc, urb, mem_flags);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Remove a queued URB from the ASL or PZL.
+ */
+static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ int ret;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_INTERRUPT:
+ ret = pzl_urb_dequeue(whc, urb, status);
+ break;
+ case PIPE_ISOCHRONOUS:
+ ret = -ENOTSUPP;
+ break;
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ default:
+ ret = asl_urb_dequeue(whc, urb, status);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Wait for all URBs to the endpoint to be completed, then delete the
+ * qset.
+ */
+static void whc_endpoint_disable(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ struct whc_qset *qset;
+
+ qset = ep->hcpriv;
+ if (qset) {
+ ep->hcpriv = NULL;
+ if (usb_endpoint_xfer_bulk(&ep->desc)
+ || usb_endpoint_xfer_control(&ep->desc))
+ asl_qset_delete(whc, qset);
+ else
+ pzl_qset_delete(whc, qset);
+ }
+}
+
+static void whc_endpoint_reset(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ struct whc_qset *qset;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ qset = ep->hcpriv;
+ if (qset) {
+ qset->remove = 1;
+ qset->reset = 1;
+
+ if (usb_endpoint_xfer_bulk(&ep->desc)
+ || usb_endpoint_xfer_control(&ep->desc))
+ queue_work(whc->workqueue, &whc->async_work);
+ else
+ queue_work(whc->workqueue, &whc->periodic_work);
+ }
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+}
+
+
+static const struct hc_driver whc_hc_driver = {
+ .description = "whci-hcd",
+ .product_desc = "Wireless host controller",
+ .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd),
+ .irq = whc_int_handler,
+ .flags = HCD_USB2,
+
+ .reset = whc_reset,
+ .start = whc_start,
+ .stop = whc_stop,
+ .get_frame_number = whc_get_frame_number,
+ .urb_enqueue = whc_urb_enqueue,
+ .urb_dequeue = whc_urb_dequeue,
+ .endpoint_disable = whc_endpoint_disable,
+ .endpoint_reset = whc_endpoint_reset,
+
+ .hub_status_data = wusbhc_rh_status_data,
+ .hub_control = wusbhc_rh_control,
+ .start_port_reset = wusbhc_rh_start_port_reset,
+};
+
+static int whc_probe(struct umc_dev *umc)
+{
+ int ret;
+ struct usb_hcd *usb_hcd;
+ struct wusbhc *wusbhc;
+ struct whc *whc;
+ struct device *dev = &umc->dev;
+
+ usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
+ if (usb_hcd == NULL) {
+ dev_err(dev, "unable to create hcd\n");
+ return -ENOMEM;
+ }
+
+ usb_hcd->wireless = 1;
+ usb_hcd->self.sg_tablesize = 2048; /* somewhat arbitrary */
+
+ wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ whc = wusbhc_to_whc(wusbhc);
+ whc->umc = umc;
+
+ ret = whc_init(whc);
+ if (ret)
+ goto error_whc_init;
+
+ wusbhc->dev = dev;
+ wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
+ if (!wusbhc->uwb_rc) {
+ ret = -ENODEV;
+ dev_err(dev, "cannot get radio controller\n");
+ goto error_uwb_rc;
+ }
+
+ if (whc->n_devices > USB_MAXCHILDREN) {
+ dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n",
+ whc->n_devices);
+ wusbhc->ports_max = USB_MAXCHILDREN;
+ } else
+ wusbhc->ports_max = whc->n_devices;
+ wusbhc->mmcies_max = whc->n_mmc_ies;
+ wusbhc->start = whc_wusbhc_start;
+ wusbhc->stop = whc_wusbhc_stop;
+ wusbhc->mmcie_add = whc_mmcie_add;
+ wusbhc->mmcie_rm = whc_mmcie_rm;
+ wusbhc->dev_info_set = whc_dev_info_set;
+ wusbhc->bwa_set = whc_bwa_set;
+ wusbhc->set_num_dnts = whc_set_num_dnts;
+ wusbhc->set_ptk = whc_set_ptk;
+ wusbhc->set_gtk = whc_set_gtk;
+
+ ret = wusbhc_create(wusbhc);
+ if (ret)
+ goto error_wusbhc_create;
+
+ ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED);
+ if (ret) {
+ dev_err(dev, "cannot add HCD: %d\n", ret);
+ goto error_usb_add_hcd;
+ }
+ device_wakeup_enable(usb_hcd->self.controller);
+
+ ret = wusbhc_b_create(wusbhc);
+ if (ret) {
+ dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret);
+ goto error_wusbhc_b_create;
+ }
+
+ whc_dbg_init(whc);
+
+ return 0;
+
+error_wusbhc_b_create:
+ usb_remove_hcd(usb_hcd);
+error_usb_add_hcd:
+ wusbhc_destroy(wusbhc);
+error_wusbhc_create:
+ uwb_rc_put(wusbhc->uwb_rc);
+error_uwb_rc:
+ whc_clean_up(whc);
+error_whc_init:
+ usb_put_hcd(usb_hcd);
+ return ret;
+}
+
+
+static void whc_remove(struct umc_dev *umc)
+{
+ struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev);
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ if (usb_hcd) {
+ whc_dbg_clean_up(whc);
+ wusbhc_b_destroy(wusbhc);
+ usb_remove_hcd(usb_hcd);
+ wusbhc_destroy(wusbhc);
+ uwb_rc_put(wusbhc->uwb_rc);
+ whc_clean_up(whc);
+ usb_put_hcd(usb_hcd);
+ }
+}
+
+static struct umc_driver whci_hc_driver = {
+ .name = "whci-hcd",
+ .cap_id = UMC_CAP_ID_WHCI_WUSB_HC,
+ .probe = whc_probe,
+ .remove = whc_remove,
+};
+
+static int __init whci_hc_driver_init(void)
+{
+ return umc_driver_register(&whci_hc_driver);
+}
+module_init(whci_hc_driver_init);
+
+static void __exit whci_hc_driver_exit(void)
+{
+ umc_driver_unregister(&whci_hc_driver);
+}
+module_exit(whci_hc_driver_exit);
+
+/* PCI device ID's that we handle (so it gets loaded) */
+static struct pci_device_id __used whci_hcd_id_table[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+ { /* empty last entry */ }
+};
+MODULE_DEVICE_TABLE(pci, whci_hcd_id_table);
+
+MODULE_DESCRIPTION("WHCI Wireless USB host controller driver");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/host/whci/hw.c b/drivers/staging/wusbcore/host/whci/hw.c
new file mode 100644
index 000000000000..e4e8914abf42
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/hw.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) hardware access helpers.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val)
+{
+ unsigned long flags;
+ u32 cmd;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ cmd = le_readl(whc->base + WUSBCMD);
+ cmd = (cmd & ~mask) | val;
+ le_writel(cmd, whc->base + WUSBCMD);
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+}
+
+/**
+ * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register
+ * @whc: the WHCI HC
+ * @cmd: command to start.
+ * @params: parameters for the command (the WUSBGENCMDPARAMS register value).
+ * @addr: pointer to any data for the command (may be NULL).
+ * @len: length of the data (if any).
+ */
+int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
+{
+ unsigned long flags;
+ dma_addr_t dma_addr;
+ int t;
+ int ret = 0;
+
+ mutex_lock(&whc->mutex);
+
+ /* Wait for previous command to complete. */
+ t = wait_event_timeout(whc->cmd_wq,
+ (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0,
+ WHC_GENCMD_TIMEOUT_MS);
+ if (t == 0) {
+ dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n",
+ le_readl(whc->base + WUSBGENCMDSTS),
+ le_readl(whc->base + WUSBGENCMDPARAMS));
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ if (addr) {
+ memcpy(whc->gen_cmd_buf, addr, len);
+ dma_addr = whc->gen_cmd_buf_dma;
+ } else
+ dma_addr = 0;
+
+ /* Poke registers to start cmd. */
+ spin_lock_irqsave(&whc->lock, flags);
+
+ le_writel(params, whc->base + WUSBGENCMDPARAMS);
+ le_writeq(dma_addr, whc->base + WUSBGENADDR);
+
+ le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd,
+ whc->base + WUSBGENCMDSTS);
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+out:
+ mutex_unlock(&whc->mutex);
+
+ return ret;
+}
+
+/**
+ * whc_hw_error - recover from a hardware error
+ * @whc: the WHCI HC that broke.
+ * @reason: a description of the failure.
+ *
+ * Recover from broken hardware with a full reset.
+ */
+void whc_hw_error(struct whc *whc, const char *reason)
+{
+ struct wusbhc *wusbhc = &whc->wusbhc;
+
+ dev_err(&whc->umc->dev, "hardware error: %s\n", reason);
+ wusbhc_reset_all(wusbhc);
+}
diff --git a/drivers/staging/wusbcore/host/whci/init.c b/drivers/staging/wusbcore/host/whci/init.c
new file mode 100644
index 000000000000..55fd458a8f30
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/init.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) initialization.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/dma-mapping.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+/*
+ * Reset the host controller.
+ */
+static void whc_hw_reset(struct whc *whc)
+{
+ le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
+ 100, "reset");
+}
+
+static void whc_hw_init_di_buf(struct whc *whc)
+{
+ int d;
+
+ /* Disable all entries in the Device Information buffer. */
+ for (d = 0; d < whc->n_devices; d++)
+ whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
+
+ le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
+}
+
+static void whc_hw_init_dn_buf(struct whc *whc)
+{
+ /* Clear the Device Notification buffer to ensure the V (valid)
+ * bits are clear. */
+ memset(whc->dn_buf, 0, 4096);
+
+ le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
+}
+
+int whc_init(struct whc *whc)
+{
+ u32 whcsparams;
+ int ret, i;
+ resource_size_t start, len;
+
+ spin_lock_init(&whc->lock);
+ mutex_init(&whc->mutex);
+ init_waitqueue_head(&whc->cmd_wq);
+ init_waitqueue_head(&whc->async_list_wq);
+ init_waitqueue_head(&whc->periodic_list_wq);
+ whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0);
+ if (whc->workqueue == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ INIT_WORK(&whc->dn_work, whc_dn_work);
+
+ INIT_WORK(&whc->async_work, scan_async_work);
+ INIT_LIST_HEAD(&whc->async_list);
+ INIT_LIST_HEAD(&whc->async_removed_list);
+
+ INIT_WORK(&whc->periodic_work, scan_periodic_work);
+ for (i = 0; i < 5; i++)
+ INIT_LIST_HEAD(&whc->periodic_list[i]);
+ INIT_LIST_HEAD(&whc->periodic_removed_list);
+
+ /* Map HC registers. */
+ start = whc->umc->resource.start;
+ len = whc->umc->resource.end - start + 1;
+ if (!request_mem_region(start, len, "whci-hc")) {
+ dev_err(&whc->umc->dev, "can't request HC region\n");
+ ret = -EBUSY;
+ goto error;
+ }
+ whc->base_phys = start;
+ whc->base = ioremap(start, len);
+ if (!whc->base) {
+ dev_err(&whc->umc->dev, "ioremap\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ whc_hw_reset(whc);
+
+ /* Read maximum number of devices, keys and MMC IEs. */
+ whcsparams = le_readl(whc->base + WHCSPARAMS);
+ whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
+ whc->n_keys = WHCSPARAMS_TO_N_KEYS(whcsparams);
+ whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
+
+ dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
+ whc->n_devices, whc->n_keys, whc->n_mmc_ies);
+
+ whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
+ sizeof(struct whc_qset), 64, 0);
+ if (whc->qset_pool == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = asl_init(whc);
+ if (ret < 0)
+ goto error;
+ ret = pzl_init(whc);
+ if (ret < 0)
+ goto error;
+
+ /* Allocate and initialize a buffer for generic commands, the
+ Device Information buffer, and the Device Notification
+ buffer. */
+
+ whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
+ &whc->gen_cmd_buf_dma, GFP_KERNEL);
+ if (whc->gen_cmd_buf == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
+ sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
+ &whc->dn_buf_dma, GFP_KERNEL);
+ if (!whc->dn_buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ whc_hw_init_dn_buf(whc);
+
+ whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
+ sizeof(struct di_buf_entry) * whc->n_devices,
+ &whc->di_buf_dma, GFP_KERNEL);
+ if (!whc->di_buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ whc_hw_init_di_buf(whc);
+
+ return 0;
+
+error:
+ whc_clean_up(whc);
+ return ret;
+}
+
+void whc_clean_up(struct whc *whc)
+{
+ resource_size_t len;
+
+ if (whc->di_buf)
+ dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
+ whc->di_buf, whc->di_buf_dma);
+ if (whc->dn_buf)
+ dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
+ whc->dn_buf, whc->dn_buf_dma);
+ if (whc->gen_cmd_buf)
+ dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
+ whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
+
+ pzl_clean_up(whc);
+ asl_clean_up(whc);
+
+ dma_pool_destroy(whc->qset_pool);
+
+ len = resource_size(&whc->umc->resource);
+ if (whc->base)
+ iounmap(whc->base);
+ if (whc->base_phys)
+ release_mem_region(whc->base_phys, len);
+
+ if (whc->workqueue)
+ destroy_workqueue(whc->workqueue);
+}
diff --git a/drivers/staging/wusbcore/host/whci/int.c b/drivers/staging/wusbcore/host/whci/int.c
new file mode 100644
index 000000000000..bdbe35e9366f
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/int.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) interrupt handling.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+static void transfer_done(struct whc *whc)
+{
+ queue_work(whc->workqueue, &whc->async_work);
+ queue_work(whc->workqueue, &whc->periodic_work);
+}
+
+irqreturn_t whc_int_handler(struct usb_hcd *hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 sts;
+
+ sts = le_readl(whc->base + WUSBSTS);
+ if (!(sts & WUSBSTS_INT_MASK))
+ return IRQ_NONE;
+ le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);
+
+ if (sts & WUSBSTS_GEN_CMD_DONE)
+ wake_up(&whc->cmd_wq);
+
+ if (sts & WUSBSTS_HOST_ERR)
+ dev_err(&whc->umc->dev, "FIXME: host system error\n");
+
+ if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
+ wake_up(&whc->async_list_wq);
+
+ if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
+ wake_up(&whc->periodic_list_wq);
+
+ if (sts & WUSBSTS_DNTS_INT)
+ queue_work(whc->workqueue, &whc->dn_work);
+
+ /*
+ * A transfer completed (see [WHCI] section 4.7.1.2 for when
+ * this occurs).
+ */
+ if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
+ transfer_done(whc);
+
+ return IRQ_HANDLED;
+}
+
+static int process_dn_buf(struct whc *whc)
+{
+ struct wusbhc *wusbhc = &whc->wusbhc;
+ struct dn_buf_entry *dn;
+ int processed = 0;
+
+ for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) {
+ if (dn->status & WHC_DN_STATUS_VALID) {
+ wusbhc_handle_dn(wusbhc, dn->src_addr,
+ (struct wusb_dn_hdr *)dn->dn_data,
+ dn->msg_size);
+ dn->status &= ~WHC_DN_STATUS_VALID;
+ processed++;
+ }
+ }
+ return processed;
+}
+
+void whc_dn_work(struct work_struct *work)
+{
+ struct whc *whc = container_of(work, struct whc, dn_work);
+ int processed;
+
+ do {
+ processed = process_dn_buf(whc);
+ } while (processed);
+}
diff --git a/drivers/staging/wusbcore/host/whci/pzl.c b/drivers/staging/wusbcore/host/whci/pzl.c
new file mode 100644
index 000000000000..6dfc075f5798
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/pzl.c
@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) periodic schedule management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+static void update_pzl_pointers(struct whc *whc, int period, u64 addr)
+{
+ switch (period) {
+ case 0:
+ whc_qset_set_link_ptr(&whc->pz_list[0], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[2], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[4], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[6], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[8], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[10], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[12], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[14], addr);
+ break;
+ case 1:
+ whc_qset_set_link_ptr(&whc->pz_list[1], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[5], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[9], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[13], addr);
+ break;
+ case 2:
+ whc_qset_set_link_ptr(&whc->pz_list[3], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[11], addr);
+ break;
+ case 3:
+ whc_qset_set_link_ptr(&whc->pz_list[7], addr);
+ break;
+ case 4:
+ whc_qset_set_link_ptr(&whc->pz_list[15], addr);
+ break;
+ }
+}
+
+/*
+ * Return the 'period' to use for this qset. The minimum interval for
+ * the endpoint is used so whatever urbs are submitted the device is
+ * polled often enough.
+ */
+static int qset_get_period(struct whc *whc, struct whc_qset *qset)
+{
+ uint8_t bInterval = qset->ep->desc.bInterval;
+
+ if (bInterval < 6)
+ bInterval = 6;
+ if (bInterval > 10)
+ bInterval = 10;
+ return bInterval - 6;
+}
+
+static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset)
+{
+ int period;
+
+ period = qset_get_period(whc, qset);
+
+ qset_clear(whc, qset);
+ list_move(&qset->list_node, &whc->periodic_list[period]);
+ qset->in_sw_list = true;
+}
+
+static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset)
+{
+ list_move(&qset->list_node, &whc->periodic_removed_list);
+ qset->in_hw_list = false;
+ qset->in_sw_list = false;
+}
+
+/**
+ * pzl_process_qset - process any recently inactivated or halted qTDs
+ * in a qset.
+ *
+ * After inactive qTDs are removed, new qTDs can be added if the
+ * urb queue still contains URBs.
+ *
+ * Returns the schedule updates required.
+ */
+static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
+{
+ enum whc_update update = 0;
+ uint32_t status = 0;
+
+ while (qset->ntds) {
+ struct whc_qtd *td;
+
+ td = &qset->qtd[qset->td_start];
+ status = le32_to_cpu(td->status);
+
+ /*
+ * Nothing to do with a still active qTD.
+ */
+ if (status & QTD_STS_ACTIVE)
+ break;
+
+ if (status & QTD_STS_HALTED) {
+ /* Ug, an error. */
+ process_halted_qtd(whc, qset, td);
+ /* A halted qTD always triggers an update
+ because the qset was either removed or
+ reactivated. */
+ update |= WHC_UPDATE_UPDATED;
+ goto done;
+ }
+
+ /* Mmm, a completed qTD. */
+ process_inactive_qtd(whc, qset, td);
+ }
+
+ if (!qset->remove)
+ update |= qset_add_qtds(whc, qset);
+
+done:
+ /*
+ * If there are no qTDs in this qset, remove it from the PZL.
+ */
+ if (qset->remove && qset->ntds == 0) {
+ pzl_qset_remove(whc, qset);
+ update |= WHC_UPDATE_REMOVED;
+ }
+
+ return update;
+}
+
+/**
+ * pzl_start - start the periodic schedule
+ * @whc: the WHCI host controller
+ *
+ * The PZL must be valid (e.g., all entries in the list should have
+ * the T bit set).
+ */
+void pzl_start(struct whc *whc)
+{
+ le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
+
+ whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED,
+ 1000, "start PZL");
+}
+
+/**
+ * pzl_stop - stop the periodic schedule
+ * @whc: the WHCI host controller
+ */
+void pzl_stop(struct whc *whc)
+{
+ whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_PERIODIC_SCHED, 0,
+ 1000, "stop PZL");
+}
+
+/**
+ * pzl_update - request a PZL update and wait for the hardware to be synced
+ * @whc: the WHCI HC
+ * @wusbcmd: WUSBCMD value to start the update.
+ *
+ * If the WUSB HC is inactive (i.e., the PZL is stopped) then the
+ * update must be skipped as the hardware may not respond to update
+ * requests.
+ */
+void pzl_update(struct whc *whc, uint32_t wusbcmd)
+{
+ struct wusbhc *wusbhc = &whc->wusbhc;
+ long t;
+
+ mutex_lock(&wusbhc->mutex);
+ if (wusbhc->active) {
+ whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
+ t = wait_event_timeout(
+ whc->periodic_list_wq,
+ (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0,
+ msecs_to_jiffies(1000));
+ if (t == 0)
+ whc_hw_error(whc, "PZL update timeout");
+ }
+ mutex_unlock(&wusbhc->mutex);
+}
+
+static void update_pzl_hw_view(struct whc *whc)
+{
+ struct whc_qset *qset, *t;
+ int period;
+ u64 tmp_qh = 0;
+
+ for (period = 0; period < 5; period++) {
+ list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
+ whc_qset_set_link_ptr(&qset->qh.link, tmp_qh);
+ tmp_qh = qset->qset_dma;
+ qset->in_hw_list = true;
+ }
+ update_pzl_pointers(whc, period, tmp_qh);
+ }
+}
+
+/**
+ * scan_periodic_work - scan the PZL for qsets to process.
+ *
+ * Process each qset in the PZL in turn and then signal the WHC that
+ * the PZL has been updated.
+ *
+ * Then start, stop or update the periodic schedule as required.
+ */
+void scan_periodic_work(struct work_struct *work)
+{
+ struct whc *whc = container_of(work, struct whc, periodic_work);
+ struct whc_qset *qset, *t;
+ enum whc_update update = 0;
+ int period;
+
+ spin_lock_irq(&whc->lock);
+
+ for (period = 4; period >= 0; period--) {
+ list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
+ if (!qset->in_hw_list)
+ update |= WHC_UPDATE_ADDED;
+ update |= pzl_process_qset(whc, qset);
+ }
+ }
+
+ if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
+ update_pzl_hw_view(whc);
+
+ spin_unlock_irq(&whc->lock);
+
+ if (update) {
+ uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB;
+ if (update & WHC_UPDATE_REMOVED)
+ wusbcmd |= WUSBCMD_PERIODIC_QSET_RM;
+ pzl_update(whc, wusbcmd);
+ }
+
+ /*
+ * Now that the PZL is updated, complete the removal of any
+ * removed qsets.
+ *
+ * If the qset was to be reset, do so and reinsert it into the
+ * PZL if it has pending transfers.
+ */
+ spin_lock_irq(&whc->lock);
+
+ list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
+ qset_remove_complete(whc, qset);
+ if (qset->reset) {
+ qset_reset(whc, qset);
+ if (!list_empty(&qset->stds)) {
+ qset_insert_in_sw_list(whc, qset);
+ queue_work(whc->workqueue, &whc->periodic_work);
+ }
+ }
+ }
+
+ spin_unlock_irq(&whc->lock);
+}
+
+/**
+ * pzl_urb_enqueue - queue an URB onto the periodic list (PZL)
+ * @whc: the WHCI host controller
+ * @urb: the URB to enqueue
+ * @mem_flags: flags for any memory allocations
+ *
+ * The qset for the endpoint is obtained and the urb queued on to it.
+ *
+ * Work is scheduled to update the hardware's view of the PZL.
+ */
+int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
+{
+ struct whc_qset *qset;
+ int err;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
+ if (err < 0) {
+ spin_unlock_irqrestore(&whc->lock, flags);
+ return err;
+ }
+
+ qset = get_qset(whc, urb, GFP_ATOMIC);
+ if (qset == NULL)
+ err = -ENOMEM;
+ else
+ err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+ if (!err) {
+ if (!qset->in_sw_list && !qset->remove)
+ qset_insert_in_sw_list(whc, qset);
+ } else
+ usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ if (!err)
+ queue_work(whc->workqueue, &whc->periodic_work);
+
+ return err;
+}
+
+/**
+ * pzl_urb_dequeue - remove an URB (qset) from the periodic list
+ * @whc: the WHCI host controller
+ * @urb: the URB to dequeue
+ * @status: the current status of the URB
+ *
+ * URBs that do yet have qTDs can simply be removed from the software
+ * queue, otherwise the qset must be removed so the qTDs can be safely
+ * removed.
+ */
+int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
+{
+ struct whc_urb *wurb = urb->hcpriv;
+ struct whc_qset *qset = wurb->qset;
+ struct whc_std *std, *t;
+ bool has_qtd = false;
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
+ if (ret < 0)
+ goto out;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+ if (std->urb == urb) {
+ if (std->qtd)
+ has_qtd = true;
+ qset_free_std(whc, std);
+ } else
+ std->qtd = NULL; /* so this std is re-added when the qset is */
+ }
+
+ if (has_qtd) {
+ pzl_qset_remove(whc, qset);
+ update_pzl_hw_view(whc);
+ wurb->status = status;
+ wurb->is_async = false;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+ } else
+ qset_remove_urb(whc, qset, urb, status);
+out:
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ return ret;
+}
+
+/**
+ * pzl_qset_delete - delete a qset from the PZL
+ */
+void pzl_qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+ qset->remove = 1;
+ queue_work(whc->workqueue, &whc->periodic_work);
+ qset_delete(whc, qset);
+}
+
+/**
+ * pzl_init - initialize the periodic zone list
+ * @whc: the WHCI host controller
+ */
+int pzl_init(struct whc *whc)
+{
+ int i;
+
+ whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16,
+ &whc->pz_list_dma, GFP_KERNEL);
+ if (whc->pz_list == NULL)
+ return -ENOMEM;
+
+ /* Set T bit on all elements in PZL. */
+ for (i = 0; i < 16; i++)
+ whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
+
+ le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
+
+ return 0;
+}
+
+/**
+ * pzl_clean_up - free PZL resources
+ * @whc: the WHCI host controller
+ *
+ * The PZL is stopped and empty.
+ */
+void pzl_clean_up(struct whc *whc)
+{
+ if (whc->pz_list)
+ dma_free_coherent(&whc->umc->dev, sizeof(u64) * 16, whc->pz_list,
+ whc->pz_list_dma);
+}
diff --git a/drivers/staging/wusbcore/host/whci/qset.c b/drivers/staging/wusbcore/host/whci/qset.c
new file mode 100644
index 000000000000..66459b77dc77
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/qset.c
@@ -0,0 +1,831 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) qset management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags)
+{
+ struct whc_qset *qset;
+ dma_addr_t dma;
+
+ qset = dma_pool_zalloc(whc->qset_pool, mem_flags, &dma);
+ if (qset == NULL)
+ return NULL;
+
+ qset->qset_dma = dma;
+ qset->whc = whc;
+
+ INIT_LIST_HEAD(&qset->list_node);
+ INIT_LIST_HEAD(&qset->stds);
+
+ return qset;
+}
+
+/**
+ * qset_fill_qh - fill the static endpoint state in a qset's QHead
+ * @qset: the qset whose QH needs initializing with static endpoint
+ * state
+ * @urb: an urb for a transfer to this endpoint
+ */
+static void qset_fill_qh(struct whc *whc, struct whc_qset *qset, struct urb *urb)
+{
+ struct usb_device *usb_dev = urb->dev;
+ struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
+ struct usb_wireless_ep_comp_descriptor *epcd;
+ bool is_out;
+ uint8_t phy_rate;
+
+ is_out = usb_pipeout(urb->pipe);
+
+ qset->max_packet = le16_to_cpu(urb->ep->desc.wMaxPacketSize);
+
+ epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra;
+ if (epcd) {
+ qset->max_seq = epcd->bMaxSequence;
+ qset->max_burst = epcd->bMaxBurst;
+ } else {
+ qset->max_seq = 2;
+ qset->max_burst = 1;
+ }
+
+ /*
+ * Initial PHY rate is 53.3 Mbit/s for control endpoints or
+ * the maximum supported by the device for other endpoints
+ * (unless limited by the user).
+ */
+ if (usb_pipecontrol(urb->pipe))
+ phy_rate = UWB_PHY_RATE_53;
+ else {
+ uint16_t phy_rates;
+
+ phy_rates = le16_to_cpu(wusb_dev->wusb_cap_descr->wPHYRates);
+ phy_rate = fls(phy_rates) - 1;
+ if (phy_rate > whc->wusbhc.phy_rate)
+ phy_rate = whc->wusbhc.phy_rate;
+ }
+
+ qset->qh.info1 = cpu_to_le32(
+ QH_INFO1_EP(usb_pipeendpoint(urb->pipe))
+ | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN)
+ | usb_pipe_to_qh_type(urb->pipe)
+ | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum))
+ | QH_INFO1_MAX_PKT_LEN(qset->max_packet)
+ );
+ qset->qh.info2 = cpu_to_le32(
+ QH_INFO2_BURST(qset->max_burst)
+ | QH_INFO2_DBP(0)
+ | QH_INFO2_MAX_COUNT(3)
+ | QH_INFO2_MAX_RETRY(3)
+ | QH_INFO2_MAX_SEQ(qset->max_seq - 1)
+ );
+ /* FIXME: where can we obtain these Tx parameters from? Why
+ * doesn't the chip know what Tx power to use? It knows the Rx
+ * strength and can presumably guess the Tx power required
+ * from that? */
+ qset->qh.info3 = cpu_to_le32(
+ QH_INFO3_TX_RATE(phy_rate)
+ | QH_INFO3_TX_PWR(0) /* 0 == max power */
+ );
+
+ qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
+}
+
+/**
+ * qset_clear - clear fields in a qset so it may be reinserted into a
+ * schedule.
+ *
+ * The sequence number and current window are not cleared (see
+ * qset_reset()).
+ */
+void qset_clear(struct whc *whc, struct whc_qset *qset)
+{
+ qset->td_start = qset->td_end = qset->ntds = 0;
+
+ qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
+ qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
+ qset->qh.err_count = 0;
+ qset->qh.scratch[0] = 0;
+ qset->qh.scratch[1] = 0;
+ qset->qh.scratch[2] = 0;
+
+ memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay));
+
+ init_completion(&qset->remove_complete);
+}
+
+/**
+ * qset_reset - reset endpoint state in a qset.
+ *
+ * Clears the sequence number and current window. This qset must not
+ * be in the ASL or PZL.
+ */
+void qset_reset(struct whc *whc, struct whc_qset *qset)
+{
+ qset->reset = 0;
+
+ qset->qh.status &= ~QH_STATUS_SEQ_MASK;
+ qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
+}
+
+/**
+ * get_qset - get the qset for an async endpoint
+ *
+ * A new qset is created if one does not already exist.
+ */
+struct whc_qset *get_qset(struct whc *whc, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct whc_qset *qset;
+
+ qset = urb->ep->hcpriv;
+ if (qset == NULL) {
+ qset = qset_alloc(whc, mem_flags);
+ if (qset == NULL)
+ return NULL;
+
+ qset->ep = urb->ep;
+ urb->ep->hcpriv = qset;
+ qset_fill_qh(whc, qset, urb);
+ }
+ return qset;
+}
+
+void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
+{
+ qset->remove = 0;
+ list_del_init(&qset->list_node);
+ complete(&qset->remove_complete);
+}
+
+/**
+ * qset_add_qtds - add qTDs for an URB to a qset
+ *
+ * Returns true if the list (ASL/PZL) must be updated because (for a
+ * WHCI 0.95 controller) an activated qTD was pointed to be iCur.
+ */
+enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset)
+{
+ struct whc_std *std;
+ enum whc_update update = 0;
+
+ list_for_each_entry(std, &qset->stds, list_node) {
+ struct whc_qtd *qtd;
+ uint32_t status;
+
+ if (qset->ntds >= WHCI_QSET_TD_MAX
+ || (qset->pause_after_urb && std->urb != qset->pause_after_urb))
+ break;
+
+ if (std->qtd)
+ continue; /* already has a qTD */
+
+ qtd = std->qtd = &qset->qtd[qset->td_end];
+
+ /* Fill in setup bytes for control transfers. */
+ if (usb_pipecontrol(std->urb->pipe))
+ memcpy(qtd->setup, std->urb->setup_packet, 8);
+
+ status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len);
+
+ if (whc_std_last(std) && usb_pipeout(std->urb->pipe))
+ status |= QTD_STS_LAST_PKT;
+
+ /*
+ * For an IN transfer the iAlt field should be set so
+ * the h/w will automatically advance to the next
+ * transfer. However, if there are 8 or more TDs
+ * remaining in this transfer then iAlt cannot be set
+ * as it could point to somewhere in this transfer.
+ */
+ if (std->ntds_remaining < WHCI_QSET_TD_MAX) {
+ int ialt;
+ ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX;
+ status |= QTD_STS_IALT(ialt);
+ } else if (usb_pipein(std->urb->pipe))
+ qset->pause_after_urb = std->urb;
+
+ if (std->num_pointers)
+ qtd->options = cpu_to_le32(QTD_OPT_IOC);
+ else
+ qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL);
+ qtd->page_list_ptr = cpu_to_le64(std->dma_addr);
+
+ qtd->status = cpu_to_le32(status);
+
+ if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end)
+ update = WHC_UPDATE_UPDATED;
+
+ if (++qset->td_end >= WHCI_QSET_TD_MAX)
+ qset->td_end = 0;
+ qset->ntds++;
+ }
+
+ return update;
+}
+
+/**
+ * qset_remove_qtd - remove the first qTD from a qset.
+ *
+ * The qTD might be still active (if it's part of a IN URB that
+ * resulted in a short read) so ensure it's deactivated.
+ */
+static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset)
+{
+ qset->qtd[qset->td_start].status = 0;
+
+ if (++qset->td_start >= WHCI_QSET_TD_MAX)
+ qset->td_start = 0;
+ qset->ntds--;
+}
+
+static void qset_copy_bounce_to_sg(struct whc *whc, struct whc_std *std)
+{
+ struct scatterlist *sg;
+ void *bounce;
+ size_t remaining, offset;
+
+ bounce = std->bounce_buf;
+ remaining = std->len;
+
+ sg = std->bounce_sg;
+ offset = std->bounce_offset;
+
+ while (remaining) {
+ size_t len;
+
+ len = min(sg->length - offset, remaining);
+ memcpy(sg_virt(sg) + offset, bounce, len);
+
+ bounce += len;
+ remaining -= len;
+
+ offset += len;
+ if (offset >= sg->length) {
+ sg = sg_next(sg);
+ offset = 0;
+ }
+ }
+
+}
+
+/**
+ * qset_free_std - remove an sTD and free it.
+ * @whc: the WHCI host controller
+ * @std: the sTD to remove and free.
+ */
+void qset_free_std(struct whc *whc, struct whc_std *std)
+{
+ list_del(&std->list_node);
+ if (std->bounce_buf) {
+ bool is_out = usb_pipeout(std->urb->pipe);
+ dma_addr_t dma_addr;
+
+ if (std->num_pointers)
+ dma_addr = le64_to_cpu(std->pl_virt[0].buf_ptr);
+ else
+ dma_addr = std->dma_addr;
+
+ dma_unmap_single(whc->wusbhc.dev, dma_addr,
+ std->len, is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (!is_out)
+ qset_copy_bounce_to_sg(whc, std);
+ kfree(std->bounce_buf);
+ }
+ if (std->pl_virt) {
+ if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
+ dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
+ std->num_pointers * sizeof(struct whc_page_list_entry),
+ DMA_TO_DEVICE);
+ kfree(std->pl_virt);
+ std->pl_virt = NULL;
+ }
+ kfree(std);
+}
+
+/**
+ * qset_remove_qtds - remove an URB's qTDs (and sTDs).
+ */
+static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset,
+ struct urb *urb)
+{
+ struct whc_std *std, *t;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+ if (std->urb != urb)
+ break;
+ if (std->qtd != NULL)
+ qset_remove_qtd(whc, qset);
+ qset_free_std(whc, std);
+ }
+}
+
+/**
+ * qset_free_stds - free any remaining sTDs for an URB.
+ */
+static void qset_free_stds(struct whc_qset *qset, struct urb *urb)
+{
+ struct whc_std *std, *t;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+ if (std->urb == urb)
+ qset_free_std(qset->whc, std);
+ }
+}
+
+static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags)
+{
+ dma_addr_t dma_addr = std->dma_addr;
+ dma_addr_t sp, ep;
+ size_t pl_len;
+ int p;
+
+ /* Short buffers don't need a page list. */
+ if (std->len <= WHCI_PAGE_SIZE) {
+ std->num_pointers = 0;
+ return 0;
+ }
+
+ sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
+ ep = dma_addr + std->len;
+ std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
+
+ pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
+ std->pl_virt = kmalloc(pl_len, mem_flags);
+ if (std->pl_virt == NULL)
+ return -ENOMEM;
+ std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) {
+ kfree(std->pl_virt);
+ return -EFAULT;
+ }
+
+ for (p = 0; p < std->num_pointers; p++) {
+ std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
+ dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
+ }
+
+ return 0;
+}
+
+/**
+ * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system.
+ */
+static void urb_dequeue_work(struct work_struct *work)
+{
+ struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work);
+ struct whc_qset *qset = wurb->qset;
+ struct whc *whc = qset->whc;
+ unsigned long flags;
+
+ if (wurb->is_async)
+ asl_update(whc, WUSBCMD_ASYNC_UPDATED
+ | WUSBCMD_ASYNC_SYNCED_DB
+ | WUSBCMD_ASYNC_QSET_RM);
+ else
+ pzl_update(whc, WUSBCMD_PERIODIC_UPDATED
+ | WUSBCMD_PERIODIC_SYNCED_DB
+ | WUSBCMD_PERIODIC_QSET_RM);
+
+ spin_lock_irqsave(&whc->lock, flags);
+ qset_remove_urb(whc, qset, wurb->urb, wurb->status);
+ spin_unlock_irqrestore(&whc->lock, flags);
+}
+
+static struct whc_std *qset_new_std(struct whc *whc, struct whc_qset *qset,
+ struct urb *urb, gfp_t mem_flags)
+{
+ struct whc_std *std;
+
+ std = kzalloc(sizeof(struct whc_std), mem_flags);
+ if (std == NULL)
+ return NULL;
+
+ std->urb = urb;
+ std->qtd = NULL;
+
+ INIT_LIST_HEAD(&std->list_node);
+ list_add_tail(&std->list_node, &qset->stds);
+
+ return std;
+}
+
+static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *urb,
+ gfp_t mem_flags)
+{
+ size_t remaining;
+ struct scatterlist *sg;
+ int i;
+ int ntds = 0;
+ struct whc_std *std = NULL;
+ struct whc_page_list_entry *new_pl_virt;
+ dma_addr_t prev_end = 0;
+ size_t pl_len;
+ int p = 0;
+
+ remaining = urb->transfer_buffer_length;
+
+ for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
+ dma_addr_t dma_addr;
+ size_t dma_remaining;
+ dma_addr_t sp, ep;
+ int num_pointers;
+
+ if (remaining == 0) {
+ break;
+ }
+
+ dma_addr = sg_dma_address(sg);
+ dma_remaining = min_t(size_t, sg_dma_len(sg), remaining);
+
+ while (dma_remaining) {
+ size_t dma_len;
+
+ /*
+ * We can use the previous std (if it exists) provided that:
+ * - the previous one ended on a page boundary.
+ * - the current one begins on a page boundary.
+ * - the previous one isn't full.
+ *
+ * If a new std is needed but the previous one
+ * was not a whole number of packets then this
+ * sg list cannot be mapped onto multiple
+ * qTDs. Return an error and let the caller
+ * sort it out.
+ */
+ if (!std
+ || (prev_end & (WHCI_PAGE_SIZE-1))
+ || (dma_addr & (WHCI_PAGE_SIZE-1))
+ || std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) {
+ if (std && std->len % qset->max_packet != 0)
+ return -EINVAL;
+ std = qset_new_std(whc, qset, urb, mem_flags);
+ if (std == NULL) {
+ return -ENOMEM;
+ }
+ ntds++;
+ p = 0;
+ }
+
+ dma_len = dma_remaining;
+
+ /*
+ * If the remainder of this element doesn't
+ * fit in a single qTD, limit the qTD to a
+ * whole number of packets. This allows the
+ * remainder to go into the next qTD.
+ */
+ if (std->len + dma_len > QTD_MAX_XFER_SIZE) {
+ dma_len = (QTD_MAX_XFER_SIZE / qset->max_packet)
+ * qset->max_packet - std->len;
+ }
+
+ std->len += dma_len;
+ std->ntds_remaining = -1; /* filled in later */
+
+ sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
+ ep = dma_addr + dma_len;
+ num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
+ std->num_pointers += num_pointers;
+
+ pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
+
+ new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
+ if (new_pl_virt == NULL) {
+ kfree(std->pl_virt);
+ std->pl_virt = NULL;
+ return -ENOMEM;
+ }
+ std->pl_virt = new_pl_virt;
+
+ for (;p < std->num_pointers; p++) {
+ std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
+ dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
+ }
+
+ prev_end = dma_addr = ep;
+ dma_remaining -= dma_len;
+ remaining -= dma_len;
+ }
+ }
+
+ /* Now the number of stds is know, go back and fill in
+ std->ntds_remaining. */
+ list_for_each_entry(std, &qset->stds, list_node) {
+ if (std->ntds_remaining == -1) {
+ pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
+ std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt,
+ pl_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
+ return -EFAULT;
+ std->ntds_remaining = ntds--;
+ }
+ }
+ return 0;
+}
+
+/**
+ * qset_add_urb_sg_linearize - add an urb with sg list, copying the data
+ *
+ * If the URB contains an sg list whose elements cannot be directly
+ * mapped to qTDs then the data must be transferred via bounce
+ * buffers.
+ */
+static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
+ struct urb *urb, gfp_t mem_flags)
+{
+ bool is_out = usb_pipeout(urb->pipe);
+ size_t max_std_len;
+ size_t remaining;
+ int ntds = 0;
+ struct whc_std *std = NULL;
+ void *bounce = NULL;
+ struct scatterlist *sg;
+ int i;
+
+ /* limit maximum bounce buffer to 16 * 3.5 KiB ~= 28 k */
+ max_std_len = qset->max_burst * qset->max_packet;
+
+ remaining = urb->transfer_buffer_length;
+
+ for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
+ size_t len;
+ size_t sg_remaining;
+ void *orig;
+
+ if (remaining == 0) {
+ break;
+ }
+
+ sg_remaining = min_t(size_t, remaining, sg->length);
+ orig = sg_virt(sg);
+
+ while (sg_remaining) {
+ if (!std || std->len == max_std_len) {
+ std = qset_new_std(whc, qset, urb, mem_flags);
+ if (std == NULL)
+ return -ENOMEM;
+ std->bounce_buf = kmalloc(max_std_len, mem_flags);
+ if (std->bounce_buf == NULL)
+ return -ENOMEM;
+ std->bounce_sg = sg;
+ std->bounce_offset = orig - sg_virt(sg);
+ bounce = std->bounce_buf;
+ ntds++;
+ }
+
+ len = min(sg_remaining, max_std_len - std->len);
+
+ if (is_out)
+ memcpy(bounce, orig, len);
+
+ std->len += len;
+ std->ntds_remaining = -1; /* filled in later */
+
+ bounce += len;
+ orig += len;
+ sg_remaining -= len;
+ remaining -= len;
+ }
+ }
+
+ /*
+ * For each of the new sTDs, map the bounce buffers, create
+ * page lists (if necessary), and fill in std->ntds_remaining.
+ */
+ list_for_each_entry(std, &qset->stds, list_node) {
+ if (std->ntds_remaining != -1)
+ continue;
+
+ std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len,
+ is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (dma_mapping_error(&whc->umc->dev, std->dma_addr))
+ return -EFAULT;
+
+ if (qset_fill_page_list(whc, std, mem_flags) < 0)
+ return -ENOMEM;
+
+ std->ntds_remaining = ntds--;
+ }
+
+ return 0;
+}
+
+/**
+ * qset_add_urb - add an urb to the qset's queue.
+ *
+ * The URB is chopped into sTDs, one for each qTD that will required.
+ * At least one qTD (and sTD) is required even if the transfer has no
+ * data (e.g., for some control transfers).
+ */
+int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct whc_urb *wurb;
+ int remaining = urb->transfer_buffer_length;
+ u64 transfer_dma = urb->transfer_dma;
+ int ntds_remaining;
+ int ret;
+
+ wurb = kzalloc(sizeof(struct whc_urb), mem_flags);
+ if (wurb == NULL)
+ goto err_no_mem;
+ urb->hcpriv = wurb;
+ wurb->qset = qset;
+ wurb->urb = urb;
+ INIT_WORK(&wurb->dequeue_work, urb_dequeue_work);
+
+ if (urb->num_sgs) {
+ ret = qset_add_urb_sg(whc, qset, urb, mem_flags);
+ if (ret == -EINVAL) {
+ qset_free_stds(qset, urb);
+ ret = qset_add_urb_sg_linearize(whc, qset, urb, mem_flags);
+ }
+ if (ret < 0)
+ goto err_no_mem;
+ return 0;
+ }
+
+ ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE);
+ if (ntds_remaining == 0)
+ ntds_remaining = 1;
+
+ while (ntds_remaining) {
+ struct whc_std *std;
+ size_t std_len;
+
+ std_len = remaining;
+ if (std_len > QTD_MAX_XFER_SIZE)
+ std_len = QTD_MAX_XFER_SIZE;
+
+ std = qset_new_std(whc, qset, urb, mem_flags);
+ if (std == NULL)
+ goto err_no_mem;
+
+ std->dma_addr = transfer_dma;
+ std->len = std_len;
+ std->ntds_remaining = ntds_remaining;
+
+ if (qset_fill_page_list(whc, std, mem_flags) < 0)
+ goto err_no_mem;
+
+ ntds_remaining--;
+ remaining -= std_len;
+ transfer_dma += std_len;
+ }
+
+ return 0;
+
+err_no_mem:
+ qset_free_stds(qset, urb);
+ return -ENOMEM;
+}
+
+/**
+ * qset_remove_urb - remove an URB from the urb queue.
+ *
+ * The URB is returned to the USB subsystem.
+ */
+void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
+ struct urb *urb, int status)
+{
+ struct wusbhc *wusbhc = &whc->wusbhc;
+ struct whc_urb *wurb = urb->hcpriv;
+
+ usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb);
+ /* Drop the lock as urb->complete() may enqueue another urb. */
+ spin_unlock(&whc->lock);
+ wusbhc_giveback_urb(wusbhc, urb, status);
+ spin_lock(&whc->lock);
+
+ kfree(wurb);
+}
+
+/**
+ * get_urb_status_from_qtd - get the completed urb status from qTD status
+ * @urb: completed urb
+ * @status: qTD status
+ */
+static int get_urb_status_from_qtd(struct urb *urb, u32 status)
+{
+ if (status & QTD_STS_HALTED) {
+ if (status & QTD_STS_DBE)
+ return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM;
+ else if (status & QTD_STS_BABBLE)
+ return -EOVERFLOW;
+ else if (status & QTD_STS_RCE)
+ return -ETIME;
+ return -EPIPE;
+ }
+ if (usb_pipein(urb->pipe)
+ && (urb->transfer_flags & URB_SHORT_NOT_OK)
+ && urb->actual_length < urb->transfer_buffer_length)
+ return -EREMOTEIO;
+ return 0;
+}
+
+/**
+ * process_inactive_qtd - process an inactive (but not halted) qTD.
+ *
+ * Update the urb with the transfer bytes from the qTD, if the urb is
+ * completely transferred or (in the case of an IN only) the LPF is
+ * set, then the transfer is complete and the urb should be returned
+ * to the system.
+ */
+void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
+ struct whc_qtd *qtd)
+{
+ struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
+ struct urb *urb = std->urb;
+ uint32_t status;
+ bool complete;
+
+ status = le32_to_cpu(qtd->status);
+
+ urb->actual_length += std->len - QTD_STS_TO_LEN(status);
+
+ if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT))
+ complete = true;
+ else
+ complete = whc_std_last(std);
+
+ qset_remove_qtd(whc, qset);
+ qset_free_std(whc, std);
+
+ /*
+ * Transfers for this URB are complete? Then return it to the
+ * USB subsystem.
+ */
+ if (complete) {
+ qset_remove_qtds(whc, qset, urb);
+ qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status));
+
+ /*
+ * If iAlt isn't valid then the hardware didn't
+ * advance iCur. Adjust the start and end pointers to
+ * match iCur.
+ */
+ if (!(status & QTD_STS_IALT_VALID))
+ qset->td_start = qset->td_end
+ = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status));
+ qset->pause_after_urb = NULL;
+ }
+}
+
+/**
+ * process_halted_qtd - process a qset with a halted qtd
+ *
+ * Remove all the qTDs for the failed URB and return the failed URB to
+ * the USB subsystem. Then remove all other qTDs so the qset can be
+ * removed.
+ *
+ * FIXME: this is the point where rate adaptation can be done. If a
+ * transfer failed because it exceeded the maximum number of retries
+ * then it could be reactivated with a slower rate without having to
+ * remove the qset.
+ */
+void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
+ struct whc_qtd *qtd)
+{
+ struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
+ struct urb *urb = std->urb;
+ int urb_status;
+
+ urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status));
+
+ qset_remove_qtds(whc, qset, urb);
+ qset_remove_urb(whc, qset, urb, urb_status);
+
+ list_for_each_entry(std, &qset->stds, list_node) {
+ if (qset->ntds == 0)
+ break;
+ qset_remove_qtd(whc, qset);
+ std->qtd = NULL;
+ }
+
+ qset->remove = 1;
+}
+
+void qset_free(struct whc *whc, struct whc_qset *qset)
+{
+ dma_pool_free(whc->qset_pool, qset, qset->qset_dma);
+}
+
+/**
+ * qset_delete - wait for a qset to be unused, then free it.
+ */
+void qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+ wait_for_completion(&qset->remove_complete);
+ qset_free(whc, qset);
+}
diff --git a/drivers/staging/wusbcore/host/whci/whcd.h b/drivers/staging/wusbcore/host/whci/whcd.h
new file mode 100644
index 000000000000..a442a2589e83
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/whcd.h
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) private header.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#ifndef __WHCD_H
+#define __WHCD_H
+
+#include <linux/workqueue.h>
+
+#include "../../../uwb/include/whci.h"
+#include "../../../uwb/include/umc.h"
+#include "whci-hc.h"
+
+/* Generic command timeout. */
+#define WHC_GENCMD_TIMEOUT_MS 100
+
+struct whc_dbg;
+
+struct whc {
+ struct wusbhc wusbhc;
+ struct umc_dev *umc;
+
+ resource_size_t base_phys;
+ void __iomem *base;
+ int irq;
+
+ u8 n_devices;
+ u8 n_keys;
+ u8 n_mmc_ies;
+
+ u64 *pz_list;
+ struct dn_buf_entry *dn_buf;
+ struct di_buf_entry *di_buf;
+ dma_addr_t pz_list_dma;
+ dma_addr_t dn_buf_dma;
+ dma_addr_t di_buf_dma;
+
+ spinlock_t lock;
+ struct mutex mutex;
+
+ void * gen_cmd_buf;
+ dma_addr_t gen_cmd_buf_dma;
+ wait_queue_head_t cmd_wq;
+
+ struct workqueue_struct *workqueue;
+ struct work_struct dn_work;
+
+ struct dma_pool *qset_pool;
+
+ struct list_head async_list;
+ struct list_head async_removed_list;
+ wait_queue_head_t async_list_wq;
+ struct work_struct async_work;
+
+ struct list_head periodic_list[5];
+ struct list_head periodic_removed_list;
+ wait_queue_head_t periodic_list_wq;
+ struct work_struct periodic_work;
+
+ struct whc_dbg *dbg;
+};
+
+#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc))
+
+/**
+ * struct whc_std - a software TD.
+ * @urb: the URB this sTD is for.
+ * @offset: start of the URB's data for this TD.
+ * @len: the length of data in the associated TD.
+ * @ntds_remaining: number of TDs (starting from this one) in this transfer.
+ *
+ * @bounce_buf: a bounce buffer if the std was from an urb with a sg
+ * list that could not be mapped to qTDs directly.
+ * @bounce_sg: the first scatterlist element bounce_buf is for.
+ * @bounce_offset: the offset into bounce_sg for the start of bounce_buf.
+ *
+ * Queued URBs may require more TDs than are available in a qset so we
+ * use a list of these "software TDs" (sTDs) to hold per-TD data.
+ */
+struct whc_std {
+ struct urb *urb;
+ size_t len;
+ int ntds_remaining;
+ struct whc_qtd *qtd;
+
+ struct list_head list_node;
+ int num_pointers;
+ dma_addr_t dma_addr;
+ struct whc_page_list_entry *pl_virt;
+
+ void *bounce_buf;
+ struct scatterlist *bounce_sg;
+ unsigned bounce_offset;
+};
+
+/**
+ * struct whc_urb - per URB host controller structure.
+ * @urb: the URB this struct is for.
+ * @qset: the qset associated to the URB.
+ * @dequeue_work: the work to remove the URB when dequeued.
+ * @is_async: the URB belongs to async sheduler or not.
+ * @status: the status to be returned when calling wusbhc_giveback_urb.
+ */
+struct whc_urb {
+ struct urb *urb;
+ struct whc_qset *qset;
+ struct work_struct dequeue_work;
+ bool is_async;
+ int status;
+};
+
+/**
+ * whc_std_last - is this sTD the URB's last?
+ * @std: the sTD to check.
+ */
+static inline bool whc_std_last(struct whc_std *std)
+{
+ return std->ntds_remaining <= 1;
+}
+
+enum whc_update {
+ WHC_UPDATE_ADDED = 0x01,
+ WHC_UPDATE_REMOVED = 0x02,
+ WHC_UPDATE_UPDATED = 0x04,
+};
+
+/* init.c */
+int whc_init(struct whc *whc);
+void whc_clean_up(struct whc *whc);
+
+/* hw.c */
+void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val);
+int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
+void whc_hw_error(struct whc *whc, const char *reason);
+
+/* wusb.c */
+int whc_wusbhc_start(struct wusbhc *wusbhc);
+void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay);
+int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+ u8 handle, struct wuie_hdr *wuie);
+int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
+int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm);
+int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
+int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots);
+int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+ const void *ptk, size_t key_size);
+int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+ const void *gtk, size_t key_size);
+int whc_set_cluster_id(struct whc *whc, u8 bcid);
+
+/* int.c */
+irqreturn_t whc_int_handler(struct usb_hcd *hcd);
+void whc_dn_work(struct work_struct *work);
+
+/* asl.c */
+void asl_start(struct whc *whc);
+void asl_stop(struct whc *whc);
+int asl_init(struct whc *whc);
+void asl_clean_up(struct whc *whc);
+int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
+void asl_qset_delete(struct whc *whc, struct whc_qset *qset);
+void scan_async_work(struct work_struct *work);
+
+/* pzl.c */
+int pzl_init(struct whc *whc);
+void pzl_clean_up(struct whc *whc);
+void pzl_start(struct whc *whc);
+void pzl_stop(struct whc *whc);
+int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
+void pzl_qset_delete(struct whc *whc, struct whc_qset *qset);
+void scan_periodic_work(struct work_struct *work);
+
+/* qset.c */
+struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags);
+void qset_free(struct whc *whc, struct whc_qset *qset);
+struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+void qset_delete(struct whc *whc, struct whc_qset *qset);
+void qset_clear(struct whc *whc, struct whc_qset *qset);
+void qset_reset(struct whc *whc, struct whc_qset *qset);
+int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
+ gfp_t mem_flags);
+void qset_free_std(struct whc *whc, struct whc_std *std);
+void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
+ struct urb *urb, int status);
+void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
+ struct whc_qtd *qtd);
+void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
+ struct whc_qtd *qtd);
+enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset);
+void qset_remove_complete(struct whc *whc, struct whc_qset *qset);
+void pzl_update(struct whc *whc, uint32_t wusbcmd);
+void asl_update(struct whc *whc, uint32_t wusbcmd);
+
+/* debug.c */
+void whc_dbg_init(struct whc *whc);
+void whc_dbg_clean_up(struct whc *whc);
+
+#endif /* #ifndef __WHCD_H */
diff --git a/drivers/staging/wusbcore/host/whci/whci-hc.h b/drivers/staging/wusbcore/host/whci/whci-hc.h
new file mode 100644
index 000000000000..5a86a57a80cc
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/whci-hc.h
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) data structures.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#ifndef _WHCI_WHCI_HC_H
+#define _WHCI_WHCI_HC_H
+
+#include <linux/list.h>
+
+/**
+ * WHCI_PAGE_SIZE - page size use by WHCI
+ *
+ * WHCI assumes that host system uses pages of 4096 octets.
+ */
+#define WHCI_PAGE_SIZE 4096
+
+
+/**
+ * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single
+ * qtd.
+ *
+ * This is 2^20 - 1.
+ */
+#define QTD_MAX_XFER_SIZE 1048575
+
+
+/**
+ * struct whc_qtd - Queue Element Transfer Descriptors (qTD)
+ *
+ * This describes the data for a bulk, control or interrupt transfer.
+ *
+ * [WHCI] section 3.2.4
+ */
+struct whc_qtd {
+ __le32 status; /*< remaining transfer len and transfer status */
+ __le32 options;
+ __le64 page_list_ptr; /*< physical pointer to data buffer page list*/
+ __u8 setup[8]; /*< setup data for control transfers */
+} __attribute__((packed));
+
+#define QTD_STS_ACTIVE (1 << 31) /* enable execution of transaction */
+#define QTD_STS_HALTED (1 << 30) /* transfer halted */
+#define QTD_STS_DBE (1 << 29) /* data buffer error */
+#define QTD_STS_BABBLE (1 << 28) /* babble detected */
+#define QTD_STS_RCE (1 << 27) /* retry count exceeded */
+#define QTD_STS_LAST_PKT (1 << 26) /* set Last Packet Flag in WUSB header */
+#define QTD_STS_INACTIVE (1 << 25) /* queue set is marked inactive */
+#define QTD_STS_IALT_VALID (1 << 23) /* iAlt field is valid */
+#define QTD_STS_IALT(i) (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */
+#define QTD_STS_LEN(l) ((l) << 0) /* transfer length */
+#define QTD_STS_TO_LEN(s) ((s) & 0x000fffff)
+
+#define QTD_OPT_IOC (1 << 1) /* page_list_ptr points to buffer directly */
+#define QTD_OPT_SMALL (1 << 0) /* interrupt on complete */
+
+/**
+ * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD)
+ *
+ * This describes the data and other parameters for an isochronous
+ * transfer.
+ *
+ * [WHCI] section 3.2.5
+ */
+struct whc_itd {
+ __le16 presentation_time; /*< presentation time for OUT transfers */
+ __u8 num_segments; /*< number of data segments in segment list */
+ __u8 status; /*< command execution status */
+ __le32 options; /*< misc transfer options */
+ __le64 page_list_ptr; /*< physical pointer to data buffer page list */
+ __le64 seg_list_ptr; /*< physical pointer to segment list */
+} __attribute__((packed));
+
+#define ITD_STS_ACTIVE (1 << 7) /* enable execution of transaction */
+#define ITD_STS_DBE (1 << 5) /* data buffer error */
+#define ITD_STS_BABBLE (1 << 4) /* babble detected */
+#define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */
+
+#define ITD_OPT_IOC (1 << 1) /* interrupt on complete */
+#define ITD_OPT_SMALL (1 << 0) /* page_list_ptr points to buffer directly */
+
+/**
+ * Page list entry.
+ *
+ * A TD's page list must contain sufficient page list entries for the
+ * total data length in the TD.
+ *
+ * [WHCI] section 3.2.4.3
+ */
+struct whc_page_list_entry {
+ __le64 buf_ptr; /*< physical pointer to buffer */
+} __attribute__((packed));
+
+/**
+ * struct whc_seg_list_entry - Segment list entry.
+ *
+ * Describes a portion of the data buffer described in the containing
+ * qTD's page list.
+ *
+ * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr
+ * + qtd->seg_list_ptr[seg].offset;
+ *
+ * Segments can't cross page boundries.
+ *
+ * [WHCI] section 3.2.5.5
+ */
+struct whc_seg_list_entry {
+ __le16 len; /*< segment length */
+ __u8 idx; /*< index into page list */
+ __u8 status; /*< segment status */
+ __le16 offset; /*< 12 bit offset into page */
+} __attribute__((packed));
+
+/**
+ * struct whc_qhead - endpoint and status information for a qset.
+ *
+ * [WHCI] section 3.2.6
+ */
+struct whc_qhead {
+ __le64 link; /*< next qset in list */
+ __le32 info1;
+ __le32 info2;
+ __le32 info3;
+ __le16 status;
+ __le16 err_count; /*< transaction error count */
+ __le32 cur_window;
+ __le32 scratch[3]; /*< h/w scratch area */
+ union {
+ struct whc_qtd qtd;
+ struct whc_itd itd;
+ } overlay;
+} __attribute__((packed));
+
+#define QH_LINK_PTR_MASK (~0x03Full)
+#define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK)
+#define QH_LINK_IQS (1 << 4) /* isochronous queue set */
+#define QH_LINK_NTDS(n) (((n) - 1) << 1) /* number of TDs in queue set */
+#define QH_LINK_T (1 << 0) /* last queue set in periodic schedule list */
+
+#define QH_INFO1_EP(e) ((e) << 0) /* endpoint number */
+#define QH_INFO1_DIR_IN (1 << 4) /* IN transfer */
+#define QH_INFO1_DIR_OUT (0 << 4) /* OUT transfer */
+#define QH_INFO1_TR_TYPE_CTRL (0x0 << 5) /* control transfer */
+#define QH_INFO1_TR_TYPE_ISOC (0x1 << 5) /* isochronous transfer */
+#define QH_INFO1_TR_TYPE_BULK (0x2 << 5) /* bulk transfer */
+#define QH_INFO1_TR_TYPE_INT (0x3 << 5) /* interrupt */
+#define QH_INFO1_TR_TYPE_LP_INT (0x7 << 5) /* low power interrupt */
+#define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8) /* index into device info buffer */
+#define QH_INFO1_SET_INACTIVE (1 << 15) /* set inactive after transfer */
+#define QH_INFO1_MAX_PKT_LEN(l) ((l) << 16) /* maximum packet length */
+
+#define QH_INFO2_BURST(b) ((b) << 0) /* maximum burst length */
+#define QH_INFO2_DBP(p) ((p) << 5) /* data burst policy (see [WUSB] table 5-7) */
+#define QH_INFO2_MAX_COUNT(c) ((c) << 8) /* max isoc/int pkts per zone */
+#define QH_INFO2_RQS (1 << 15) /* reactivate queue set */
+#define QH_INFO2_MAX_RETRY(r) ((r) << 16) /* maximum transaction retries */
+#define QH_INFO2_MAX_SEQ(s) ((s) << 20) /* maximum sequence number */
+#define QH_INFO3_MAX_DELAY(d) ((d) << 0) /* maximum stream delay in 125 us units (isoc only) */
+#define QH_INFO3_INTERVAL(i) ((i) << 16) /* segment interval in 125 us units (isoc only) */
+
+#define QH_INFO3_TX_RATE(r) ((r) << 24) /* PHY rate (see [ECMA-368] section 10.3.1.1) */
+#define QH_INFO3_TX_PWR(p) ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */
+
+#define QH_STATUS_FLOW_CTRL (1 << 15)
+#define QH_STATUS_ICUR(i) ((i) << 5)
+#define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7)
+#define QH_STATUS_SEQ_MASK 0x1f
+
+/**
+ * usb_pipe_to_qh_type - USB core pipe type to QH transfer type
+ *
+ * Returns the QH type field for a USB core pipe type.
+ */
+static inline unsigned usb_pipe_to_qh_type(unsigned pipe)
+{
+ static const unsigned type[] = {
+ [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC,
+ [PIPE_INTERRUPT] = QH_INFO1_TR_TYPE_INT,
+ [PIPE_CONTROL] = QH_INFO1_TR_TYPE_CTRL,
+ [PIPE_BULK] = QH_INFO1_TR_TYPE_BULK,
+ };
+ return type[usb_pipetype(pipe)];
+}
+
+/**
+ * Maxiumum number of TDs in a qset.
+ */
+#define WHCI_QSET_TD_MAX 8
+
+/**
+ * struct whc_qset - WUSB data transfers to a specific endpoint
+ * @qh: the QHead of this qset
+ * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt
+ * transfers)
+ * @itd: up to 8 iTDs (for qsets for isochronous transfers)
+ * @qset_dma: DMA address for this qset
+ * @whc: WHCI HC this qset is for
+ * @ep: endpoint
+ * @stds: list of sTDs queued to this qset
+ * @ntds: number of qTDs queued (not necessarily the same as nTDs
+ * field in the QH)
+ * @td_start: index of the first qTD in the list
+ * @td_end: index of next free qTD in the list (provided
+ * ntds < WHCI_QSET_TD_MAX)
+ *
+ * Queue Sets (qsets) are added to the asynchronous schedule list
+ * (ASL) or the periodic zone list (PZL).
+ *
+ * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate).
+ * Each TD may refer to at most 1 MiB of data. If a single transfer
+ * has > 8MiB of data, TDs can be reused as they are completed since
+ * the TD list is used as a circular buffer. Similarly, several
+ * (smaller) transfers may be queued in a qset.
+ *
+ * WHCI controllers may cache portions of the qsets in the ASL and
+ * PZL, requiring the WHCD to inform the WHC that the lists have been
+ * updated (fields changed or qsets inserted or removed). For safe
+ * insertion and removal of qsets from the lists the schedule must be
+ * stopped to avoid races in updating the QH link pointers.
+ *
+ * Since the HC is free to execute qsets in any order, all transfers
+ * to an endpoint should use the same qset to ensure transfers are
+ * executed in the order they're submitted.
+ *
+ * [WHCI] section 3.2.3
+ */
+struct whc_qset {
+ struct whc_qhead qh;
+ union {
+ struct whc_qtd qtd[WHCI_QSET_TD_MAX];
+ struct whc_itd itd[WHCI_QSET_TD_MAX];
+ };
+
+ /* private data for WHCD */
+ dma_addr_t qset_dma;
+ struct whc *whc;
+ struct usb_host_endpoint *ep;
+ struct list_head stds;
+ int ntds;
+ int td_start;
+ int td_end;
+ struct list_head list_node;
+ unsigned in_sw_list:1;
+ unsigned in_hw_list:1;
+ unsigned remove:1;
+ unsigned reset:1;
+ struct urb *pause_after_urb;
+ struct completion remove_complete;
+ uint16_t max_packet;
+ uint8_t max_burst;
+ uint8_t max_seq;
+};
+
+static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target)
+{
+ if (target)
+ *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target);
+ else
+ *ptr = QH_LINK_T;
+}
+
+/**
+ * struct di_buf_entry - Device Information (DI) buffer entry.
+ *
+ * There's one of these per connected device.
+ */
+struct di_buf_entry {
+ __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */
+ __le32 addr_sec_info; /*< addressing and security info */
+ __le32 reserved[7];
+} __attribute__((packed));
+
+#define WHC_DI_SECURE (1 << 31)
+#define WHC_DI_DISABLE (1 << 30)
+#define WHC_DI_KEY_IDX(k) ((k) << 8)
+#define WHC_DI_KEY_IDX_MASK 0x0000ff00
+#define WHC_DI_DEV_ADDR(a) ((a) << 0)
+#define WHC_DI_DEV_ADDR_MASK 0x000000ff
+
+/**
+ * struct dn_buf_entry - Device Notification (DN) buffer entry.
+ *
+ * [WHCI] section 3.2.8
+ */
+struct dn_buf_entry {
+ __u8 msg_size; /*< number of octets of valid DN data */
+ __u8 reserved1;
+ __u8 src_addr; /*< source address */
+ __u8 status; /*< buffer entry status */
+ __le32 tkid; /*< TKID for source device, valid if secure bit is set */
+ __u8 dn_data[56]; /*< up to 56 octets of DN data */
+} __attribute__((packed));
+
+#define WHC_DN_STATUS_VALID (1 << 7) /* buffer entry is valid */
+#define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */
+
+#define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry))
+
+/* The Add MMC IE WUSB Generic Command may take up to 256 bytes of
+ data. [WHCI] section 2.4.7. */
+#define WHC_GEN_CMD_DATA_LEN 256
+
+/*
+ * HC registers.
+ *
+ * [WHCI] section 2.4
+ */
+
+#define WHCIVERSION 0x00
+
+#define WHCSPARAMS 0x04
+# define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff)
+# define WHCSPARAMS_TO_N_KEYS(p) (((p) >> 8) & 0xff)
+# define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f)
+
+#define WUSBCMD 0x08
+# define WUSBCMD_BCID(b) ((b) << 16)
+# define WUSBCMD_BCID_MASK (0xff << 16)
+# define WUSBCMD_ASYNC_QSET_RM (1 << 12)
+# define WUSBCMD_PERIODIC_QSET_RM (1 << 11)
+# define WUSBCMD_WUSBSI(s) ((s) << 8)
+# define WUSBCMD_WUSBSI_MASK (0x7 << 8)
+# define WUSBCMD_ASYNC_SYNCED_DB (1 << 7)
+# define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6)
+# define WUSBCMD_ASYNC_UPDATED (1 << 5)
+# define WUSBCMD_PERIODIC_UPDATED (1 << 4)
+# define WUSBCMD_ASYNC_EN (1 << 3)
+# define WUSBCMD_PERIODIC_EN (1 << 2)
+# define WUSBCMD_WHCRESET (1 << 1)
+# define WUSBCMD_RUN (1 << 0)
+
+#define WUSBSTS 0x0c
+# define WUSBSTS_ASYNC_SCHED (1 << 15)
+# define WUSBSTS_PERIODIC_SCHED (1 << 14)
+# define WUSBSTS_DNTS_SCHED (1 << 13)
+# define WUSBSTS_HCHALTED (1 << 12)
+# define WUSBSTS_GEN_CMD_DONE (1 << 9)
+# define WUSBSTS_CHAN_TIME_ROLLOVER (1 << 8)
+# define WUSBSTS_DNTS_OVERFLOW (1 << 7)
+# define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6)
+# define WUSBSTS_HOST_ERR (1 << 5)
+# define WUSBSTS_ASYNC_SCHED_SYNCED (1 << 4)
+# define WUSBSTS_PERIODIC_SCHED_SYNCED (1 << 3)
+# define WUSBSTS_DNTS_INT (1 << 2)
+# define WUSBSTS_ERR_INT (1 << 1)
+# define WUSBSTS_INT (1 << 0)
+# define WUSBSTS_INT_MASK 0x3ff
+
+#define WUSBINTR 0x10
+# define WUSBINTR_GEN_CMD_DONE (1 << 9)
+# define WUSBINTR_CHAN_TIME_ROLLOVER (1 << 8)
+# define WUSBINTR_DNTS_OVERFLOW (1 << 7)
+# define WUSBINTR_BPST_ADJUSTMENT_CHANGED (1 << 6)
+# define WUSBINTR_HOST_ERR (1 << 5)
+# define WUSBINTR_ASYNC_SCHED_SYNCED (1 << 4)
+# define WUSBINTR_PERIODIC_SCHED_SYNCED (1 << 3)
+# define WUSBINTR_DNTS_INT (1 << 2)
+# define WUSBINTR_ERR_INT (1 << 1)
+# define WUSBINTR_INT (1 << 0)
+# define WUSBINTR_ALL 0x3ff
+
+#define WUSBGENCMDSTS 0x14
+# define WUSBGENCMDSTS_ACTIVE (1 << 31)
+# define WUSBGENCMDSTS_ERROR (1 << 24)
+# define WUSBGENCMDSTS_IOC (1 << 23)
+# define WUSBGENCMDSTS_MMCIE_ADD 0x01
+# define WUSBGENCMDSTS_MMCIE_RM 0x02
+# define WUSBGENCMDSTS_SET_MAS 0x03
+# define WUSBGENCMDSTS_CHAN_STOP 0x04
+# define WUSBGENCMDSTS_RWP_EN 0x05
+
+#define WUSBGENCMDPARAMS 0x18
+#define WUSBGENADDR 0x20
+#define WUSBASYNCLISTADDR 0x28
+#define WUSBDNTSBUFADDR 0x30
+#define WUSBDEVICEINFOADDR 0x38
+
+#define WUSBSETSECKEYCMD 0x40
+# define WUSBSETSECKEYCMD_SET (1 << 31)
+# define WUSBSETSECKEYCMD_ERASE (1 << 30)
+# define WUSBSETSECKEYCMD_GTK (1 << 8)
+# define WUSBSETSECKEYCMD_IDX(i) ((i) << 0)
+
+#define WUSBTKID 0x44
+#define WUSBSECKEY 0x48
+#define WUSBPERIODICLISTBASE 0x58
+#define WUSBMASINDEX 0x60
+
+#define WUSBDNTSCTRL 0x64
+# define WUSBDNTSCTRL_ACTIVE (1 << 31)
+# define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8)
+# define WUSBDNTSCTRL_SLOTS(s) ((s) << 0)
+
+#define WUSBTIME 0x68
+# define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff
+
+#define WUSBBPST 0x6c
+#define WUSBDIBUPDATED 0x70
+
+#endif /* #ifndef _WHCI_WHCI_HC_H */
diff --git a/drivers/staging/wusbcore/host/whci/wusb.c b/drivers/staging/wusbcore/host/whci/wusb.c
new file mode 100644
index 000000000000..6d0068ab35e4
--- /dev/null
+++ b/drivers/staging/wusbcore/host/whci/wusb.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) WUSB operations.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+static int whc_update_di(struct whc *whc, int idx)
+{
+ int offset = idx / 32;
+ u32 bit = 1 << (idx % 32);
+
+ le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
+
+ return whci_wait_for(&whc->umc->dev,
+ whc->base + WUSBDIBUPDATED + offset, bit, 0,
+ 100, "DI update");
+}
+
+/*
+ * WHCI starts MMCs based on there being a valid GTK so these need
+ * only start/stop the asynchronous and periodic schedules and send a
+ * channel stop command.
+ */
+
+int whc_wusbhc_start(struct wusbhc *wusbhc)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ asl_start(whc);
+ pzl_start(whc);
+
+ return 0;
+}
+
+void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 stop_time, now_time;
+ int ret;
+
+ pzl_stop(whc);
+ asl_stop(whc);
+
+ now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
+ stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
+ ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
+ if (ret == 0)
+ msleep(delay);
+}
+
+int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+ u8 handle, struct wuie_hdr *wuie)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 params;
+
+ params = (interval << 24)
+ | (repeat_cnt << 16)
+ | (wuie->bLength << 8)
+ | handle;
+
+ return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength);
+}
+
+int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 params;
+
+ params = handle;
+
+ return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0);
+}
+
+int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ if (stream_index >= 0)
+ whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index));
+
+ return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm));
+}
+
+int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ int idx = wusb_dev->port_idx;
+ struct di_buf_entry *di = &whc->di_buf[idx];
+ int ret;
+
+ mutex_lock(&whc->mutex);
+
+ uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability);
+ di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK);
+ di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr);
+
+ ret = whc_update_di(whc, idx);
+
+ mutex_unlock(&whc->mutex);
+
+ return ret;
+}
+
+/*
+ * Set the number of Device Notification Time Slots (DNTS) and enable
+ * device notifications.
+ */
+int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 dntsctrl;
+
+ dntsctrl = WUSBDNTSCTRL_ACTIVE
+ | WUSBDNTSCTRL_INTERVAL(interval)
+ | WUSBDNTSCTRL_SLOTS(slots);
+
+ le_writel(dntsctrl, whc->base + WUSBDNTSCTRL);
+
+ return 0;
+}
+
+static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid,
+ const void *key, size_t key_size, bool is_gtk)
+{
+ uint32_t setkeycmd;
+ uint32_t seckey[4];
+ int i;
+ int ret;
+
+ memcpy(seckey, key, key_size);
+ setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index);
+ if (is_gtk)
+ setkeycmd |= WUSBSETSECKEYCMD_GTK;
+
+ le_writel(tkid, whc->base + WUSBTKID);
+ for (i = 0; i < 4; i++)
+ le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i);
+ le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD);
+
+ ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD,
+ WUSBSETSECKEYCMD_SET, 0, 100, "set key");
+
+ return ret;
+}
+
+/**
+ * whc_set_ptk - set the PTK to use for a device.
+ *
+ * The index into the key table for this PTK is the same as the
+ * device's port index.
+ */
+int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+ const void *ptk, size_t key_size)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ struct di_buf_entry *di = &whc->di_buf[port_idx];
+ int ret;
+
+ mutex_lock(&whc->mutex);
+
+ if (ptk) {
+ ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false);
+ if (ret)
+ goto out;
+
+ di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK;
+ di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx);
+ } else
+ di->addr_sec_info &= ~WHC_DI_SECURE;
+
+ ret = whc_update_di(whc, port_idx);
+out:
+ mutex_unlock(&whc->mutex);
+ return ret;
+}
+
+/**
+ * whc_set_gtk - set the GTK for subsequent broadcast packets
+ *
+ * The GTK is stored in the last entry in the key table (the previous
+ * N_DEVICES entries are for the per-device PTKs).
+ */
+int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+ const void *gtk, size_t key_size)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ int ret;
+
+ mutex_lock(&whc->mutex);
+
+ ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true);
+
+ mutex_unlock(&whc->mutex);
+
+ return ret;
+}
+
+int whc_set_cluster_id(struct whc *whc, u8 bcid)
+{
+ whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid));
+ return 0;
+}
diff --git a/drivers/staging/wusbcore/include/association.h b/drivers/staging/wusbcore/include/association.h
new file mode 100644
index 000000000000..d7f3cb9b9db5
--- /dev/null
+++ b/drivers/staging/wusbcore/include/association.h
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB - Cable Based Association
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ */
+#ifndef __LINUX_USB_ASSOCIATION_H
+#define __LINUX_USB_ASSOCIATION_H
+
+
+/*
+ * Association attributes
+ *
+ * Association Models Supplement to WUSB 1.0 T[3-1]
+ *
+ * Each field in the structures has it's ID, it's length and then the
+ * value. This is the actual definition of the field's ID and its
+ * length.
+ */
+struct wusb_am_attr {
+ __u8 id;
+ __u8 len;
+};
+
+/* Different fields defined by the spec */
+#define WUSB_AR_AssociationTypeId { .id = cpu_to_le16(0x0000), .len = cpu_to_le16(2) }
+#define WUSB_AR_AssociationSubTypeId { .id = cpu_to_le16(0x0001), .len = cpu_to_le16(2) }
+#define WUSB_AR_Length { .id = cpu_to_le16(0x0002), .len = cpu_to_le16(4) }
+#define WUSB_AR_AssociationStatus { .id = cpu_to_le16(0x0004), .len = cpu_to_le16(4) }
+#define WUSB_AR_LangID { .id = cpu_to_le16(0x0008), .len = cpu_to_le16(2) }
+#define WUSB_AR_DeviceFriendlyName { .id = cpu_to_le16(0x000b), .len = cpu_to_le16(64) } /* max */
+#define WUSB_AR_HostFriendlyName { .id = cpu_to_le16(0x000c), .len = cpu_to_le16(64) } /* max */
+#define WUSB_AR_CHID { .id = cpu_to_le16(0x1000), .len = cpu_to_le16(16) }
+#define WUSB_AR_CDID { .id = cpu_to_le16(0x1001), .len = cpu_to_le16(16) }
+#define WUSB_AR_ConnectionContext { .id = cpu_to_le16(0x1002), .len = cpu_to_le16(48) }
+#define WUSB_AR_BandGroups { .id = cpu_to_le16(0x1004), .len = cpu_to_le16(2) }
+
+/* CBAF Control Requests (AMS1.0[T4-1] */
+enum {
+ CBAF_REQ_GET_ASSOCIATION_INFORMATION = 0x01,
+ CBAF_REQ_GET_ASSOCIATION_REQUEST,
+ CBAF_REQ_SET_ASSOCIATION_RESPONSE
+};
+
+/*
+ * CBAF USB-interface defitions
+ *
+ * No altsettings, one optional interrupt endpoint.
+ */
+enum {
+ CBAF_IFACECLASS = 0xef,
+ CBAF_IFACESUBCLASS = 0x03,
+ CBAF_IFACEPROTOCOL = 0x01,
+};
+
+/* Association Information (AMS1.0[T4-3]) */
+struct wusb_cbaf_assoc_info {
+ __le16 Length;
+ __u8 NumAssociationRequests;
+ __le16 Flags;
+ __u8 AssociationRequestsArray[];
+} __attribute__((packed));
+
+/* Association Request (AMS1.0[T4-4]) */
+struct wusb_cbaf_assoc_request {
+ __u8 AssociationDataIndex;
+ __u8 Reserved;
+ __le16 AssociationTypeId;
+ __le16 AssociationSubTypeId;
+ __le32 AssociationTypeInfoSize;
+} __attribute__((packed));
+
+enum {
+ AR_TYPE_WUSB = 0x0001,
+ AR_TYPE_WUSB_RETRIEVE_HOST_INFO = 0x0000,
+ AR_TYPE_WUSB_ASSOCIATE = 0x0001,
+};
+
+/* Association Attribute header (AMS1.0[3.8]) */
+struct wusb_cbaf_attr_hdr {
+ __le16 id;
+ __le16 len;
+} __attribute__((packed));
+
+/* Host Info (AMS1.0[T4-7]) (yeah, more headers and fields...) */
+struct wusb_cbaf_host_info {
+ struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+ __le16 AssociationTypeId;
+ struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+ __le16 AssociationSubTypeId;
+ struct wusb_cbaf_attr_hdr CHID_hdr;
+ struct wusb_ckhdid CHID;
+ struct wusb_cbaf_attr_hdr LangID_hdr;
+ __le16 LangID;
+ struct wusb_cbaf_attr_hdr HostFriendlyName_hdr;
+ __u8 HostFriendlyName[];
+} __attribute__((packed));
+
+/* Device Info (AMS1.0[T4-8])
+ *
+ * I still don't get this tag'n'header stuff for each goddamn
+ * field...
+ */
+struct wusb_cbaf_device_info {
+ struct wusb_cbaf_attr_hdr Length_hdr;
+ __le32 Length;
+ struct wusb_cbaf_attr_hdr CDID_hdr;
+ struct wusb_ckhdid CDID;
+ struct wusb_cbaf_attr_hdr BandGroups_hdr;
+ __le16 BandGroups;
+ struct wusb_cbaf_attr_hdr LangID_hdr;
+ __le16 LangID;
+ struct wusb_cbaf_attr_hdr DeviceFriendlyName_hdr;
+ __u8 DeviceFriendlyName[];
+} __attribute__((packed));
+
+/* Connection Context; CC_DATA - Success case (AMS1.0[T4-9]) */
+struct wusb_cbaf_cc_data {
+ struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+ __le16 AssociationTypeId;
+ struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+ __le16 AssociationSubTypeId;
+ struct wusb_cbaf_attr_hdr Length_hdr;
+ __le32 Length;
+ struct wusb_cbaf_attr_hdr ConnectionContext_hdr;
+ struct wusb_ckhdid CHID;
+ struct wusb_ckhdid CDID;
+ struct wusb_ckhdid CK;
+ struct wusb_cbaf_attr_hdr BandGroups_hdr;
+ __le16 BandGroups;
+} __attribute__((packed));
+
+/* CC_DATA - Failure case (AMS1.0[T4-10]) */
+struct wusb_cbaf_cc_data_fail {
+ struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+ __le16 AssociationTypeId;
+ struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+ __le16 AssociationSubTypeId;
+ struct wusb_cbaf_attr_hdr Length_hdr;
+ __le16 Length;
+ struct wusb_cbaf_attr_hdr AssociationStatus_hdr;
+ __u32 AssociationStatus;
+} __attribute__((packed));
+
+#endif /* __LINUX_USB_ASSOCIATION_H */
diff --git a/drivers/staging/wusbcore/include/wusb-wa.h b/drivers/staging/wusbcore/include/wusb-wa.h
new file mode 100644
index 000000000000..64a840b5106e
--- /dev/null
+++ b/drivers/staging/wusbcore/include/wusb-wa.h
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Wire Adapter constants and structures.
+ *
+ * Copyright (C) 2005-2006 Intel Corporation.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * FIXME: docs
+ * FIXME: organize properly, group logically
+ *
+ * All the event structures are defined in uwb/spec.h, as they are
+ * common to the WHCI and WUSB radio control interfaces.
+ *
+ * References:
+ * [WUSB] Wireless Universal Serial Bus Specification, revision 1.0, ch8
+ */
+#ifndef __LINUX_USB_WUSB_WA_H
+#define __LINUX_USB_WUSB_WA_H
+
+/**
+ * Radio Command Request for the Radio Control Interface
+ *
+ * Radio Control Interface command and event codes are the same as
+ * WHCI, and listed in include/linux/uwb.h:UWB_RC_{CMD,EVT}_*
+ */
+enum {
+ WA_EXEC_RC_CMD = 40, /* Radio Control command Request */
+};
+
+/* Wireless Adapter Requests ([WUSB] table 8-51) */
+enum {
+ WUSB_REQ_ADD_MMC_IE = 20,
+ WUSB_REQ_REMOVE_MMC_IE = 21,
+ WUSB_REQ_SET_NUM_DNTS = 22,
+ WUSB_REQ_SET_CLUSTER_ID = 23,
+ WUSB_REQ_SET_DEV_INFO = 24,
+ WUSB_REQ_GET_TIME = 25,
+ WUSB_REQ_SET_STREAM_IDX = 26,
+ WUSB_REQ_SET_WUSB_MAS = 27,
+ WUSB_REQ_CHAN_STOP = 28,
+};
+
+
+/* Wireless Adapter WUSB Channel Time types ([WUSB] table 8-52) */
+enum {
+ WUSB_TIME_ADJ = 0,
+ WUSB_TIME_BPST = 1,
+ WUSB_TIME_WUSB = 2,
+};
+
+enum {
+ WA_ENABLE = 0x01,
+ WA_RESET = 0x02,
+ RPIPE_PAUSE = 0x1,
+ RPIPE_STALL = 0x2,
+};
+
+/* Responses from Get Status request ([WUSB] section 8.3.1.6) */
+enum {
+ WA_STATUS_ENABLED = 0x01,
+ WA_STATUS_RESETTING = 0x02
+};
+
+enum rpipe_crs {
+ RPIPE_CRS_CTL = 0x01,
+ RPIPE_CRS_ISO = 0x02,
+ RPIPE_CRS_BULK = 0x04,
+ RPIPE_CRS_INTR = 0x08
+};
+
+/**
+ * RPipe descriptor ([WUSB] section 8.5.2.11)
+ *
+ * FIXME: explain rpipes
+ */
+struct usb_rpipe_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+ __le16 wRPipeIndex;
+ __le16 wRequests;
+ __le16 wBlocks; /* rw if 0 */
+ __le16 wMaxPacketSize; /* rw */
+ union {
+ u8 dwa_bHSHubAddress; /* rw: DWA. */
+ u8 hwa_bMaxBurst; /* rw: HWA. */
+ };
+ union {
+ u8 dwa_bHSHubPort; /* rw: DWA. */
+ u8 hwa_bDeviceInfoIndex; /* rw: HWA. */
+ };
+ u8 bSpeed; /* rw: xfer rate 'enum uwb_phy_rate' */
+ union {
+ u8 dwa_bDeviceAddress; /* rw: DWA Target device address. */
+ u8 hwa_reserved; /* rw: HWA. */
+ };
+ u8 bEndpointAddress; /* rw: Target EP address */
+ u8 bDataSequence; /* ro: Current Data sequence */
+ __le32 dwCurrentWindow; /* ro */
+ u8 bMaxDataSequence; /* ro?: max supported seq */
+ u8 bInterval; /* rw: */
+ u8 bOverTheAirInterval; /* rw: */
+ u8 bmAttribute; /* ro? */
+ u8 bmCharacteristics; /* ro? enum rpipe_attr, supported xsactions */
+ u8 bmRetryOptions; /* rw? */
+ __le16 wNumTransactionErrors; /* rw */
+} __attribute__ ((packed));
+
+/**
+ * Wire Adapter Notification types ([WUSB] sections 8.4.5 & 8.5.4)
+ *
+ * These are the notifications coming on the notification endpoint of
+ * an HWA and a DWA.
+ */
+enum wa_notif_type {
+ DWA_NOTIF_RWAKE = 0x91,
+ DWA_NOTIF_PORTSTATUS = 0x92,
+ WA_NOTIF_TRANSFER = 0x93,
+ HWA_NOTIF_BPST_ADJ = 0x94,
+ HWA_NOTIF_DN = 0x95,
+};
+
+/**
+ * Wire Adapter notification header
+ *
+ * Notifications coming from a wire adapter use a common header
+ * defined in [WUSB] sections 8.4.5 & 8.5.4.
+ */
+struct wa_notif_hdr {
+ u8 bLength;
+ u8 bNotifyType; /* enum wa_notif_type */
+} __packed;
+
+/**
+ * HWA DN Received notification [(WUSB] section 8.5.4.2)
+ *
+ * The DNData is specified in WUSB1.0[7.6]. For each device
+ * notification we received, we just need to dispatch it.
+ *
+ * @dndata: this is really an array of notifications, but all start
+ * with the same header.
+ */
+struct hwa_notif_dn {
+ struct wa_notif_hdr hdr;
+ u8 bSourceDeviceAddr; /* from errata 2005/07 */
+ u8 bmAttributes;
+ struct wusb_dn_hdr dndata[];
+} __packed;
+
+/* [WUSB] section 8.3.3 */
+enum wa_xfer_type {
+ WA_XFER_TYPE_CTL = 0x80,
+ WA_XFER_TYPE_BI = 0x81, /* bulk/interrupt */
+ WA_XFER_TYPE_ISO = 0x82,
+ WA_XFER_RESULT = 0x83,
+ WA_XFER_ABORT = 0x84,
+ WA_XFER_ISO_PACKET_INFO = 0xA0,
+ WA_XFER_ISO_PACKET_STATUS = 0xA1,
+};
+
+/* [WUSB] section 8.3.3 */
+struct wa_xfer_hdr {
+ u8 bLength; /* 0x18 */
+ u8 bRequestType; /* 0x80 WA_REQUEST_TYPE_CTL */
+ __le16 wRPipe; /* RPipe index */
+ __le32 dwTransferID; /* Host-assigned ID */
+ __le32 dwTransferLength; /* Length of data to xfer */
+ u8 bTransferSegment;
+} __packed;
+
+struct wa_xfer_ctl {
+ struct wa_xfer_hdr hdr;
+ u8 bmAttribute;
+ __le16 wReserved;
+ struct usb_ctrlrequest baSetupData;
+} __packed;
+
+struct wa_xfer_bi {
+ struct wa_xfer_hdr hdr;
+ u8 bReserved;
+ __le16 wReserved;
+} __packed;
+
+/* [WUSB] section 8.5.5 */
+struct wa_xfer_hwaiso {
+ struct wa_xfer_hdr hdr;
+ u8 bReserved;
+ __le16 wPresentationTime;
+ __le32 dwNumOfPackets;
+} __packed;
+
+struct wa_xfer_packet_info_hwaiso {
+ __le16 wLength;
+ u8 bPacketType;
+ u8 bReserved;
+ __le16 PacketLength[0];
+} __packed;
+
+struct wa_xfer_packet_status_len_hwaiso {
+ __le16 PacketLength;
+ __le16 PacketStatus;
+} __packed;
+
+struct wa_xfer_packet_status_hwaiso {
+ __le16 wLength;
+ u8 bPacketType;
+ u8 bReserved;
+ struct wa_xfer_packet_status_len_hwaiso PacketStatus[0];
+} __packed;
+
+/* [WUSB] section 8.3.3.5 */
+struct wa_xfer_abort {
+ u8 bLength;
+ u8 bRequestType;
+ __le16 wRPipe; /* RPipe index */
+ __le32 dwTransferID; /* Host-assigned ID */
+} __packed;
+
+/**
+ * WA Transfer Complete notification ([WUSB] section 8.3.3.3)
+ *
+ */
+struct wa_notif_xfer {
+ struct wa_notif_hdr hdr;
+ u8 bEndpoint;
+ u8 Reserved;
+} __packed;
+
+/** Transfer result basic codes [WUSB] table 8-15 */
+enum {
+ WA_XFER_STATUS_SUCCESS,
+ WA_XFER_STATUS_HALTED,
+ WA_XFER_STATUS_DATA_BUFFER_ERROR,
+ WA_XFER_STATUS_BABBLE,
+ WA_XFER_RESERVED,
+ WA_XFER_STATUS_NOT_FOUND,
+ WA_XFER_STATUS_INSUFFICIENT_RESOURCE,
+ WA_XFER_STATUS_TRANSACTION_ERROR,
+ WA_XFER_STATUS_ABORTED,
+ WA_XFER_STATUS_RPIPE_NOT_READY,
+ WA_XFER_INVALID_FORMAT,
+ WA_XFER_UNEXPECTED_SEGMENT_NUMBER,
+ WA_XFER_STATUS_RPIPE_TYPE_MISMATCH,
+};
+
+/** [WUSB] section 8.3.3.4 */
+struct wa_xfer_result {
+ struct wa_notif_hdr hdr;
+ __le32 dwTransferID;
+ __le32 dwTransferLength;
+ u8 bTransferSegment;
+ u8 bTransferStatus;
+ __le32 dwNumOfPackets;
+} __packed;
+
+/**
+ * Wire Adapter Class Descriptor ([WUSB] section 8.5.2.7).
+ *
+ * NOTE: u16 fields are read Little Endian from the hardware.
+ *
+ * @bNumPorts is the original max number of devices that the host can
+ * connect; we might chop this so the stack can handle
+ * it. In case you need to access it, use wusbhc->ports_max
+ * if it is a Wireless USB WA.
+ */
+struct usb_wa_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+ __le16 bcdWAVersion;
+ u8 bNumPorts; /* don't use!! */
+ u8 bmAttributes; /* Reserved == 0 */
+ __le16 wNumRPipes;
+ __le16 wRPipeMaxBlock;
+ u8 bRPipeBlockSize;
+ u8 bPwrOn2PwrGood;
+ u8 bNumMMCIEs;
+ u8 DeviceRemovable; /* FIXME: in DWA this is up to 16 bytes */
+} __packed;
+
+/**
+ * HWA Device Information Buffer (WUSB1.0[T8.54])
+ */
+struct hwa_dev_info {
+ u8 bmDeviceAvailability[32]; /* FIXME: ignored for now */
+ u8 bDeviceAddress;
+ __le16 wPHYRates;
+ u8 bmDeviceAttribute;
+} __packed;
+
+#endif /* #ifndef __LINUX_USB_WUSB_WA_H */
diff --git a/drivers/staging/wusbcore/include/wusb.h b/drivers/staging/wusbcore/include/wusb.h
new file mode 100644
index 000000000000..09771d1da7bc
--- /dev/null
+++ b/drivers/staging/wusbcore/include/wusb.h
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Standard Definitions
+ * Event Size Tables
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * FIXME: docs
+ * FIXME: organize properly, group logically
+ *
+ * All the event structures are defined in uwb/spec.h, as they are
+ * common to the WHCI and WUSB radio control interfaces.
+ */
+
+#ifndef __WUSB_H__
+#define __WUSB_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/usb/ch9.h>
+#include <linux/param.h>
+#include "../../uwb/include/spec.h"
+
+/**
+ * WUSB Information Element header
+ *
+ * I don't know why, they decided to make it different to the MBOA MAC
+ * IE Header; beats me.
+ */
+struct wuie_hdr {
+ u8 bLength;
+ u8 bIEIdentifier;
+} __attribute__((packed));
+
+enum {
+ WUIE_ID_WCTA = 0x80,
+ WUIE_ID_CONNECTACK,
+ WUIE_ID_HOST_INFO,
+ WUIE_ID_CHANGE_ANNOUNCE,
+ WUIE_ID_DEVICE_DISCONNECT,
+ WUIE_ID_HOST_DISCONNECT,
+ WUIE_ID_KEEP_ALIVE = 0x89,
+ WUIE_ID_ISOCH_DISCARD,
+ WUIE_ID_RESET_DEVICE,
+};
+
+/**
+ * Maximum number of array elements in a WUSB IE.
+ *
+ * WUSB1.0[7.5 before table 7-38] says that in WUSB IEs that
+ * are "arrays" have to limited to 4 elements. So we define it
+ * like that to ease up and submit only the neeed size.
+ */
+#define WUIE_ELT_MAX 4
+
+/**
+ * Wrapper for the data that defines a CHID, a CDID or a CK
+ *
+ * WUSB defines that CHIDs, CDIDs and CKs are a 16 byte string of
+ * data. In order to avoid confusion and enforce types, we wrap it.
+ *
+ * Make it packed, as we use it in some hw definitions.
+ */
+struct wusb_ckhdid {
+ u8 data[16];
+} __attribute__((packed));
+
+static const struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } };
+
+#define WUSB_CKHDID_STRSIZE (3 * sizeof(struct wusb_ckhdid) + 1)
+
+/**
+ * WUSB IE: Host Information (WUSB1.0[7.5.2])
+ *
+ * Used to provide information about the host to the Wireless USB
+ * devices in range (CHID can be used as an ASCII string).
+ */
+struct wuie_host_info {
+ struct wuie_hdr hdr;
+ __le16 attributes;
+ struct wusb_ckhdid CHID;
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Connect Ack (WUSB1.0[7.5.1])
+ *
+ * Used to acknowledge device connect requests. See note for
+ * WUIE_ELT_MAX.
+ */
+struct wuie_connect_ack {
+ struct wuie_hdr hdr;
+ struct {
+ struct wusb_ckhdid CDID;
+ u8 bDeviceAddress; /* 0 means unused */
+ u8 bReserved;
+ } blk[WUIE_ELT_MAX];
+} __attribute__((packed));
+
+/**
+ * WUSB IE Host Information Element, Connect Availability
+ *
+ * WUSB1.0[7.5.2], bmAttributes description
+ */
+enum {
+ WUIE_HI_CAP_RECONNECT = 0,
+ WUIE_HI_CAP_LIMITED,
+ WUIE_HI_CAP_RESERVED,
+ WUIE_HI_CAP_ALL,
+};
+
+/**
+ * WUSB IE: Channel Stop (WUSB1.0[7.5.8])
+ *
+ * Tells devices the host is going to stop sending MMCs and will disappear.
+ */
+struct wuie_channel_stop {
+ struct wuie_hdr hdr;
+ u8 attributes;
+ u8 timestamp[3];
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Keepalive (WUSB1.0[7.5.9])
+ *
+ * Ask device(s) to send keepalives.
+ */
+struct wuie_keep_alive {
+ struct wuie_hdr hdr;
+ u8 bDeviceAddress[WUIE_ELT_MAX];
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Reset device (WUSB1.0[7.5.11])
+ *
+ * Tell device to reset; in all truth, we can fit 4 CDIDs, but we only
+ * use it for one at the time...
+ *
+ * In any case, this request is a wee bit silly: why don't they target
+ * by address??
+ */
+struct wuie_reset {
+ struct wuie_hdr hdr;
+ struct wusb_ckhdid CDID;
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Disconnect device (WUSB1.0[7.5.11])
+ *
+ * Tell device to disconnect; we can fit 4 addresses, but we only use
+ * it for one at the time...
+ */
+struct wuie_disconnect {
+ struct wuie_hdr hdr;
+ u8 bDeviceAddress;
+ u8 padding;
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Host disconnect ([WUSB] section 7.5.5)
+ *
+ * Tells all connected devices to disconnect.
+ */
+struct wuie_host_disconnect {
+ struct wuie_hdr hdr;
+} __attribute__((packed));
+
+/**
+ * WUSB Device Notification header (WUSB1.0[7.6])
+ */
+struct wusb_dn_hdr {
+ u8 bType;
+ u8 notifdata[];
+} __attribute__((packed));
+
+/** Device Notification codes (WUSB1.0[Table 7-54]) */
+enum WUSB_DN {
+ WUSB_DN_CONNECT = 0x01,
+ WUSB_DN_DISCONNECT = 0x02,
+ WUSB_DN_EPRDY = 0x03,
+ WUSB_DN_MASAVAILCHANGED = 0x04,
+ WUSB_DN_RWAKE = 0x05,
+ WUSB_DN_SLEEP = 0x06,
+ WUSB_DN_ALIVE = 0x07,
+};
+
+/** WUSB Device Notification Connect */
+struct wusb_dn_connect {
+ struct wusb_dn_hdr hdr;
+ __le16 attributes;
+ struct wusb_ckhdid CDID;
+} __attribute__((packed));
+
+static inline int wusb_dn_connect_prev_dev_addr(const struct wusb_dn_connect *dn)
+{
+ return le16_to_cpu(dn->attributes) & 0xff;
+}
+
+static inline int wusb_dn_connect_new_connection(const struct wusb_dn_connect *dn)
+{
+ return (le16_to_cpu(dn->attributes) >> 8) & 0x1;
+}
+
+static inline int wusb_dn_connect_beacon_behavior(const struct wusb_dn_connect *dn)
+{
+ return (le16_to_cpu(dn->attributes) >> 9) & 0x03;
+}
+
+/** Device is alive (aka: pong) (WUSB1.0[7.6.7]) */
+struct wusb_dn_alive {
+ struct wusb_dn_hdr hdr;
+} __attribute__((packed));
+
+/** Device is disconnecting (WUSB1.0[7.6.2]) */
+struct wusb_dn_disconnect {
+ struct wusb_dn_hdr hdr;
+} __attribute__((packed));
+
+/* General constants */
+enum {
+ WUSB_TRUST_TIMEOUT_MS = 4000, /* [WUSB] section 4.15.1 */
+};
+
+/*
+ * WUSB Crypto stuff (WUSB1.0[6])
+ */
+
+extern const char *wusb_et_name(u8);
+
+/**
+ * WUSB key index WUSB1.0[7.3.2.4], for usage when setting keys for
+ * the host or the device.
+ */
+static inline u8 wusb_key_index(int index, int type, int originator)
+{
+ return (originator << 6) | (type << 4) | index;
+}
+
+#define WUSB_KEY_INDEX_TYPE_PTK 0 /* for HWA only */
+#define WUSB_KEY_INDEX_TYPE_ASSOC 1
+#define WUSB_KEY_INDEX_TYPE_GTK 2
+#define WUSB_KEY_INDEX_ORIGINATOR_HOST 0
+#define WUSB_KEY_INDEX_ORIGINATOR_DEVICE 1
+/* bits 0-3 used for the key index. */
+#define WUSB_KEY_INDEX_MAX 15
+
+/* A CCM Nonce, defined in WUSB1.0[6.4.1] */
+struct aes_ccm_nonce {
+ u8 sfn[6]; /* Little Endian */
+ u8 tkid[3]; /* LE */
+ struct uwb_dev_addr dest_addr;
+ struct uwb_dev_addr src_addr;
+} __attribute__((packed));
+
+/* A CCM operation label, defined on WUSB1.0[6.5.x] */
+struct aes_ccm_label {
+ u8 data[14];
+} __attribute__((packed));
+
+/*
+ * Input to the key derivation sequence defined in
+ * WUSB1.0[6.5.1]. Rest of the data is in the CCM Nonce passed to the
+ * PRF function.
+ */
+struct wusb_keydvt_in {
+ u8 hnonce[16];
+ u8 dnonce[16];
+} __attribute__((packed));
+
+/*
+ * Output from the key derivation sequence defined in
+ * WUSB1.0[6.5.1].
+ */
+struct wusb_keydvt_out {
+ u8 kck[16];
+ u8 ptk[16];
+} __attribute__((packed));
+
+/* Pseudo Random Function WUSB1.0[6.5] */
+extern int wusb_crypto_init(void);
+extern void wusb_crypto_exit(void);
+extern ssize_t wusb_prf(void *out, size_t out_size,
+ const u8 key[16], const struct aes_ccm_nonce *_n,
+ const struct aes_ccm_label *a,
+ const void *b, size_t blen, size_t len);
+
+static inline int wusb_prf_64(void *out, size_t out_size, const u8 key[16],
+ const struct aes_ccm_nonce *n,
+ const struct aes_ccm_label *a,
+ const void *b, size_t blen)
+{
+ return wusb_prf(out, out_size, key, n, a, b, blen, 64);
+}
+
+static inline int wusb_prf_128(void *out, size_t out_size, const u8 key[16],
+ const struct aes_ccm_nonce *n,
+ const struct aes_ccm_label *a,
+ const void *b, size_t blen)
+{
+ return wusb_prf(out, out_size, key, n, a, b, blen, 128);
+}
+
+static inline int wusb_prf_256(void *out, size_t out_size, const u8 key[16],
+ const struct aes_ccm_nonce *n,
+ const struct aes_ccm_label *a,
+ const void *b, size_t blen)
+{
+ return wusb_prf(out, out_size, key, n, a, b, blen, 256);
+}
+
+/* Key derivation WUSB1.0[6.5.1] */
+static inline int wusb_key_derive(struct wusb_keydvt_out *keydvt_out,
+ const u8 key[16],
+ const struct aes_ccm_nonce *n,
+ const struct wusb_keydvt_in *keydvt_in)
+{
+ const struct aes_ccm_label a = { .data = "Pair-wise keys" };
+ return wusb_prf_256(keydvt_out, sizeof(*keydvt_out), key, n, &a,
+ keydvt_in, sizeof(*keydvt_in));
+}
+
+/*
+ * Out-of-band MIC Generation WUSB1.0[6.5.2]
+ *
+ * Compute the MIC over @key, @n and @hs and place it in @mic_out.
+ *
+ * @mic_out: Where to place the 8 byte MIC tag
+ * @key: KCK from the derivation process
+ * @n: CCM nonce, n->sfn == 0, TKID as established in the
+ * process.
+ * @hs: Handshake struct for phase 2 of the 4-way.
+ * hs->bStatus and hs->bReserved are zero.
+ * hs->bMessageNumber is 2 (WUSB1.0[7.3.2.5.2]
+ * hs->dest_addr is the device's USB address padded with 0
+ * hs->src_addr is the hosts's UWB device address
+ * hs->mic is ignored (as we compute that value).
+ */
+static inline int wusb_oob_mic(u8 mic_out[8], const u8 key[16],
+ const struct aes_ccm_nonce *n,
+ const struct usb_handshake *hs)
+{
+ const struct aes_ccm_label a = { .data = "out-of-bandMIC" };
+ return wusb_prf_64(mic_out, 8, key, n, &a,
+ hs, sizeof(*hs) - sizeof(hs->MIC));
+}
+
+#endif /* #ifndef __WUSB_H__ */
diff --git a/drivers/staging/wusbcore/mmc.c b/drivers/staging/wusbcore/mmc.c
new file mode 100644
index 000000000000..881e1f20d718
--- /dev/null
+++ b/drivers/staging/wusbcore/mmc.c
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * MMC (Microscheduled Management Command) handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * WUIEs and MMC IEs...well, they are almost the same at the end. MMC
+ * IEs are Wireless USB IEs that go into the MMC period...[what is
+ * that? look in Design-overview.txt].
+ *
+ *
+ * This is a simple subsystem to keep track of which IEs are being
+ * sent by the host in the MMC period.
+ *
+ * For each WUIE we ask to send, we keep it in an array, so we can
+ * request its removal later, or replace the content. They are tracked
+ * by pointer, so be sure to use the same pointer if you want to
+ * remove it or update the contents.
+ *
+ * FIXME:
+ * - add timers that autoremove intervalled IEs?
+ */
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "include/wusb.h"
+#include "wusbhc.h"
+
+/* Initialize the MMCIEs handling mechanism */
+int wusbhc_mmcie_create(struct wusbhc *wusbhc)
+{
+ u8 mmcies = wusbhc->mmcies_max;
+ wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL);
+ if (wusbhc->mmcie == NULL)
+ return -ENOMEM;
+ mutex_init(&wusbhc->mmcie_mutex);
+ return 0;
+}
+
+/* Release resources used by the MMCIEs handling mechanism */
+void wusbhc_mmcie_destroy(struct wusbhc *wusbhc)
+{
+ kfree(wusbhc->mmcie);
+}
+
+/*
+ * Add or replace an MMC Wireless USB IE.
+ *
+ * @interval: See WUSB1.0[8.5.3.1]
+ * @repeat_cnt: See WUSB1.0[8.5.3.1]
+ * @handle: See WUSB1.0[8.5.3.1]
+ * @wuie: Pointer to the header of the WUSB IE data to add.
+ * MUST BE allocated in a kmalloc buffer (no stack or
+ * vmalloc).
+ * THE CALLER ALWAYS OWNS THE POINTER (we don't free it
+ * on remove, we just forget about it).
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Goes over the *whole* @wusbhc->mmcie array looking for (a) the
+ * first free spot and (b) if @wuie is already in the array (aka:
+ * transmitted in the MMCs) the spot were it is.
+ *
+ * If present, we "overwrite it" (update).
+ *
+ *
+ * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38.
+ * The host uses the handle as the 'sort' index. We
+ * allocate the last one always for the WUIE_ID_HOST_INFO, and
+ * the rest, first come first serve in inverse order.
+ *
+ * Host software must make sure that it adds the other IEs in
+ * the right order... the host hardware is responsible for
+ * placing the WCTA IEs in the right place with the other IEs
+ * set by host software.
+ *
+ * NOTE: we can access wusbhc->wa_descr without locking because it is
+ * read only.
+ */
+int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+ struct wuie_hdr *wuie)
+{
+ int result = -ENOBUFS;
+ unsigned handle, itr;
+
+ /* Search a handle, taking into account the ordering */
+ mutex_lock(&wusbhc->mmcie_mutex);
+ switch (wuie->bIEIdentifier) {
+ case WUIE_ID_HOST_INFO:
+ /* Always last */
+ handle = wusbhc->mmcies_max - 1;
+ break;
+ case WUIE_ID_ISOCH_DISCARD:
+ dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x "
+ "unimplemented\n", wuie->bIEIdentifier);
+ result = -ENOSYS;
+ goto error_unlock;
+ default:
+ /* search for it or find the last empty slot */
+ handle = ~0;
+ for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) {
+ if (wusbhc->mmcie[itr] == wuie) {
+ handle = itr;
+ break;
+ }
+ if (wusbhc->mmcie[itr] == NULL)
+ handle = itr;
+ }
+ if (handle == ~0)
+ goto error_unlock;
+ }
+ result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle,
+ wuie);
+ if (result >= 0)
+ wusbhc->mmcie[handle] = wuie;
+error_unlock:
+ mutex_unlock(&wusbhc->mmcie_mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_mmcie_set);
+
+/*
+ * Remove an MMC IE previously added with wusbhc_mmcie_set()
+ *
+ * @wuie Pointer used to add the WUIE
+ */
+void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie)
+{
+ int result;
+ unsigned handle, itr;
+
+ mutex_lock(&wusbhc->mmcie_mutex);
+ for (itr = 0; itr < wusbhc->mmcies_max; itr++) {
+ if (wusbhc->mmcie[itr] == wuie) {
+ handle = itr;
+ goto found;
+ }
+ }
+ mutex_unlock(&wusbhc->mmcie_mutex);
+ return;
+
+found:
+ result = (wusbhc->mmcie_rm)(wusbhc, handle);
+ if (result == 0)
+ wusbhc->mmcie[itr] = NULL;
+ mutex_unlock(&wusbhc->mmcie_mutex);
+}
+EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
+
+static int wusbhc_mmc_start(struct wusbhc *wusbhc)
+{
+ int ret;
+
+ mutex_lock(&wusbhc->mutex);
+ ret = wusbhc->start(wusbhc);
+ if (ret >= 0)
+ wusbhc->active = 1;
+ mutex_unlock(&wusbhc->mutex);
+
+ return ret;
+}
+
+static void wusbhc_mmc_stop(struct wusbhc *wusbhc)
+{
+ mutex_lock(&wusbhc->mutex);
+ wusbhc->active = 0;
+ wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
+ mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * wusbhc_start - start transmitting MMCs and accepting connections
+ * @wusbhc: the HC to start
+ *
+ * Establishes a cluster reservation, enables device connections, and
+ * starts MMCs with appropriate DNTS parameters.
+ */
+int wusbhc_start(struct wusbhc *wusbhc)
+{
+ int result;
+ struct device *dev = wusbhc->dev;
+
+ WARN_ON(wusbhc->wuie_host_info != NULL);
+ BUG_ON(wusbhc->uwb_rc == NULL);
+
+ result = wusbhc_rsv_establish(wusbhc);
+ if (result < 0) {
+ dev_err(dev, "cannot establish cluster reservation: %d\n",
+ result);
+ goto error_rsv_establish;
+ }
+
+ result = wusbhc_devconnect_start(wusbhc);
+ if (result < 0) {
+ dev_err(dev, "error enabling device connections: %d\n",
+ result);
+ goto error_devconnect_start;
+ }
+
+ result = wusbhc_sec_start(wusbhc);
+ if (result < 0) {
+ dev_err(dev, "error starting security in the HC: %d\n",
+ result);
+ goto error_sec_start;
+ }
+
+ result = wusbhc->set_num_dnts(wusbhc, wusbhc->dnts_interval,
+ wusbhc->dnts_num_slots);
+ if (result < 0) {
+ dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
+ goto error_set_num_dnts;
+ }
+ result = wusbhc_mmc_start(wusbhc);
+ if (result < 0) {
+ dev_err(dev, "error starting wusbch: %d\n", result);
+ goto error_wusbhc_start;
+ }
+
+ return 0;
+
+error_wusbhc_start:
+ wusbhc_sec_stop(wusbhc);
+error_set_num_dnts:
+error_sec_start:
+ wusbhc_devconnect_stop(wusbhc);
+error_devconnect_start:
+ wusbhc_rsv_terminate(wusbhc);
+error_rsv_establish:
+ return result;
+}
+
+/*
+ * wusbhc_stop - stop transmitting MMCs
+ * @wusbhc: the HC to stop
+ *
+ * Stops the WUSB channel and removes the cluster reservation.
+ */
+void wusbhc_stop(struct wusbhc *wusbhc)
+{
+ wusbhc_mmc_stop(wusbhc);
+ wusbhc_sec_stop(wusbhc);
+ wusbhc_devconnect_stop(wusbhc);
+ wusbhc_rsv_terminate(wusbhc);
+}
+
+/*
+ * Set/reset/update a new CHID
+ *
+ * Depending on the previous state of the MMCs, start, stop or change
+ * the sent MMC. This effectively switches the host controller on and
+ * off (radio wise).
+ */
+int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
+{
+ int result = 0;
+
+ if (memcmp(chid, &wusb_ckhdid_zero, sizeof(*chid)) == 0)
+ chid = NULL;
+
+ mutex_lock(&wusbhc->mutex);
+ if (chid) {
+ if (wusbhc->active) {
+ mutex_unlock(&wusbhc->mutex);
+ return -EBUSY;
+ }
+ wusbhc->chid = *chid;
+ }
+
+ /* register with UWB if we haven't already since we are about to start
+ the radio. */
+ if ((chid) && (wusbhc->uwb_rc == NULL)) {
+ wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent);
+ if (wusbhc->uwb_rc == NULL) {
+ result = -ENODEV;
+ dev_err(wusbhc->dev,
+ "Cannot get associated UWB Host Controller\n");
+ goto error_rc_get;
+ }
+
+ result = wusbhc_pal_register(wusbhc);
+ if (result < 0) {
+ dev_err(wusbhc->dev, "Cannot register as a UWB PAL\n");
+ goto error_pal_register;
+ }
+ }
+ mutex_unlock(&wusbhc->mutex);
+
+ if (chid)
+ result = uwb_radio_start(&wusbhc->pal);
+ else if (wusbhc->uwb_rc)
+ uwb_radio_stop(&wusbhc->pal);
+
+ return result;
+
+error_pal_register:
+ uwb_rc_put(wusbhc->uwb_rc);
+ wusbhc->uwb_rc = NULL;
+error_rc_get:
+ mutex_unlock(&wusbhc->mutex);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_chid_set);
diff --git a/drivers/staging/wusbcore/pal.c b/drivers/staging/wusbcore/pal.c
new file mode 100644
index 000000000000..30f569131471
--- /dev/null
+++ b/drivers/staging/wusbcore/pal.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * UWB Protocol Adaptation Layer (PAL) glue.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include "wusbhc.h"
+
+static void wusbhc_channel_changed(struct uwb_pal *pal, int channel)
+{
+ struct wusbhc *wusbhc = container_of(pal, struct wusbhc, pal);
+
+ dev_dbg(wusbhc->dev, "%s: channel = %d\n", __func__, channel);
+ if (channel < 0)
+ wusbhc_stop(wusbhc);
+ else
+ wusbhc_start(wusbhc);
+}
+
+/**
+ * wusbhc_pal_register - register the WUSB HC as a UWB PAL
+ * @wusbhc: the WUSB HC
+ */
+int wusbhc_pal_register(struct wusbhc *wusbhc)
+{
+ uwb_pal_init(&wusbhc->pal);
+
+ wusbhc->pal.name = "wusbhc";
+ wusbhc->pal.device = wusbhc->usb_hcd.self.controller;
+ wusbhc->pal.rc = wusbhc->uwb_rc;
+ wusbhc->pal.channel_changed = wusbhc_channel_changed;
+
+ return uwb_pal_register(&wusbhc->pal);
+}
+
+/**
+ * wusbhc_pal_unregister - unregister the WUSB HC as a UWB PAL
+ * @wusbhc: the WUSB HC
+ */
+void wusbhc_pal_unregister(struct wusbhc *wusbhc)
+{
+ if (wusbhc->uwb_rc)
+ uwb_pal_unregister(&wusbhc->pal);
+}
diff --git a/drivers/staging/wusbcore/reservation.c b/drivers/staging/wusbcore/reservation.c
new file mode 100644
index 000000000000..b921faac698b
--- /dev/null
+++ b/drivers/staging/wusbcore/reservation.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB cluster reservation management
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+
+#include "../uwb/uwb.h"
+#include "wusbhc.h"
+
+/*
+ * WUSB cluster reservations are multicast reservations with the
+ * broadcast cluster ID (BCID) as the target DevAddr.
+ *
+ * FIXME: consider adjusting the reservation depending on what devices
+ * are attached.
+ */
+
+static int wusbhc_bwa_set(struct wusbhc *wusbhc, u8 stream,
+ const struct uwb_mas_bm *mas)
+{
+ if (mas == NULL)
+ mas = &uwb_mas_bm_zero;
+ return wusbhc->bwa_set(wusbhc, stream, mas);
+}
+
+/**
+ * wusbhc_rsv_complete_cb - WUSB HC reservation complete callback
+ * @rsv: the reservation
+ *
+ * Either set or clear the HC's view of the reservation.
+ *
+ * FIXME: when a reservation is denied the HC should be stopped.
+ */
+static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)
+{
+ struct wusbhc *wusbhc = rsv->pal_priv;
+ struct device *dev = wusbhc->dev;
+ struct uwb_mas_bm mas;
+
+ dev_dbg(dev, "%s: state = %d\n", __func__, rsv->state);
+ switch (rsv->state) {
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ uwb_rsv_get_usable_mas(rsv, &mas);
+ dev_dbg(dev, "established reservation: %*pb\n",
+ UWB_NUM_MAS, mas.bm);
+ wusbhc_bwa_set(wusbhc, rsv->stream, &mas);
+ break;
+ case UWB_RSV_STATE_NONE:
+ dev_dbg(dev, "removed reservation\n");
+ wusbhc_bwa_set(wusbhc, 0, NULL);
+ break;
+ default:
+ dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state);
+ break;
+ }
+}
+
+
+/**
+ * wusbhc_rsv_establish - establish a reservation for the cluster
+ * @wusbhc: the WUSB HC requesting a bandwidth reservation
+ */
+int wusbhc_rsv_establish(struct wusbhc *wusbhc)
+{
+ struct uwb_rc *rc = wusbhc->uwb_rc;
+ struct uwb_rsv *rsv;
+ struct uwb_dev_addr bcid;
+ int ret;
+
+ if (rc == NULL)
+ return -ENODEV;
+
+ rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);
+ if (rsv == NULL)
+ return -ENOMEM;
+
+ bcid.data[0] = wusbhc->cluster_id;
+ bcid.data[1] = 0;
+
+ rsv->target.type = UWB_RSV_TARGET_DEVADDR;
+ rsv->target.devaddr = bcid;
+ rsv->type = UWB_DRP_TYPE_PRIVATE;
+ rsv->max_mas = 256; /* try to get as much as possible */
+ rsv->min_mas = 15; /* one MAS per zone */
+ rsv->max_interval = 1; /* max latency is one zone */
+ rsv->is_multicast = true;
+
+ ret = uwb_rsv_establish(rsv);
+ if (ret == 0)
+ wusbhc->rsv = rsv;
+ else
+ uwb_rsv_destroy(rsv);
+ return ret;
+}
+
+
+/**
+ * wusbhc_rsv_terminate - terminate the cluster reservation
+ * @wusbhc: the WUSB host whose reservation is to be terminated
+ */
+void wusbhc_rsv_terminate(struct wusbhc *wusbhc)
+{
+ if (wusbhc->rsv) {
+ uwb_rsv_terminate(wusbhc->rsv);
+ uwb_rsv_destroy(wusbhc->rsv);
+ wusbhc->rsv = NULL;
+ }
+}
diff --git a/drivers/staging/wusbcore/rh.c b/drivers/staging/wusbcore/rh.c
new file mode 100644
index 000000000000..20c08cd9dcbf
--- /dev/null
+++ b/drivers/staging/wusbcore/rh.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * Root Hub operations
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * We fake a root hub that has fake ports (as many as simultaneous
+ * devices the Wireless USB Host Controller can deal with). For each
+ * port we keep an state in @wusbhc->port[index] identical to the one
+ * specified in the USB2.0[ch11] spec and some extra device
+ * information that complements the one in 'struct usb_device' (as
+ * this lacs a hcpriv pointer).
+ *
+ * Note this is common to WHCI and HWA host controllers.
+ *
+ * Through here we enable most of the state changes that the USB stack
+ * will use to connect or disconnect devices. We need to do some
+ * forced adaptation of Wireless USB device states vs. wired:
+ *
+ * USB: WUSB:
+ *
+ * Port Powered-off port slot n/a
+ * Powered-on port slot available
+ * Disconnected port slot available
+ * Connected port slot assigned device
+ * device sent DN_Connect
+ * device was authenticated
+ * Enabled device is authenticated, transitioned
+ * from unauth -> auth -> default address
+ * -> enabled
+ * Reset disconnect
+ * Disable disconnect
+ *
+ * This maps the standard USB port states with the WUSB device states
+ * so we can fake ports without having to modify the USB stack.
+ *
+ * FIXME: this process will change in the future
+ *
+ *
+ * ENTRY POINTS
+ *
+ * Our entry points into here are, as in hcd.c, the USB stack root hub
+ * ops defined in the usb_hcd struct:
+ *
+ * wusbhc_rh_status_data() Provide hub and port status data bitmap
+ *
+ * wusbhc_rh_control() Execution of all the major requests
+ * you can do to a hub (Set|Clear
+ * features, get descriptors, status, etc).
+ *
+ * wusbhc_rh_[suspend|resume]() That
+ *
+ * wusbhc_rh_start_port_reset() ??? unimplemented
+ */
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "wusbhc.h"
+
+/*
+ * Reset a fake port
+ *
+ * Using a Reset Device IE is too heavyweight as it causes the device
+ * to enter the UnConnected state and leave the cluster, this can mean
+ * that when the device reconnects it is connected to a different fake
+ * port.
+ *
+ * Instead, reset authenticated devices with a SetAddress(0), followed
+ * by a SetAddresss(AuthAddr).
+ *
+ * For unauthenticated devices just pretend to reset but do nothing.
+ * If the device initialization continues to fail it will eventually
+ * time out after TrustTimeout and enter the UnConnected state.
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Supposedly we are the only thread accesing @wusbhc->port; in any
+ * case, maybe we should move the mutex locking from
+ * wusbhc_devconnect_auth() to here.
+ *
+ * @port_idx refers to the wusbhc's port index, not the USB port number
+ */
+static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
+{
+ int result = 0;
+ struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx);
+ struct wusb_dev *wusb_dev = port->wusb_dev;
+
+ if (wusb_dev == NULL)
+ return -ENOTCONN;
+
+ port->status |= USB_PORT_STAT_RESET;
+ port->change |= USB_PORT_STAT_C_RESET;
+
+ if (wusb_dev->addr & WUSB_DEV_ADDR_UNAUTH)
+ result = 0;
+ else
+ result = wusb_dev_update_address(wusbhc, wusb_dev);
+
+ port->status &= ~USB_PORT_STAT_RESET;
+ port->status |= USB_PORT_STAT_ENABLE;
+ port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE;
+
+ return result;
+}
+
+/*
+ * Return the hub change status bitmap
+ *
+ * The bits in the change status bitmap are cleared when a
+ * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4].
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * WARNING!! This gets called from atomic context; we cannot get the
+ * mutex--the only race condition we can find is some bit
+ * changing just after we copy it, which shouldn't be too
+ * big of a problem [and we can't make it an spinlock
+ * because other parts need to take it and sleep] .
+ *
+ * @usb_hcd is refcounted, so it won't disappear under us
+ * and before killing a host, the polling of the root hub
+ * would be stopped anyway.
+ */
+int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ size_t cnt, size, bits_set = 0;
+
+ /* WE DON'T LOCK, see comment */
+ /* round up to bytes. Hub bit is bit 0 so add 1. */
+ size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8);
+
+ /* clear the output buffer. */
+ memset(_buf, 0, size);
+ /* set the bit for each changed port. */
+ for (cnt = 0; cnt < wusbhc->ports_max; cnt++) {
+
+ if (wusb_port_by_idx(wusbhc, cnt)->change) {
+ const int bitpos = cnt+1;
+
+ _buf[bitpos/8] |= (1 << (bitpos % 8));
+ bits_set++;
+ }
+ }
+
+ return bits_set ? size : 0;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
+
+/*
+ * Return the hub's descriptor
+ *
+ * NOTE: almost cut and paste from ehci-hub.c
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked
+ */
+static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue,
+ u16 wIndex,
+ struct usb_hub_descriptor *descr,
+ u16 wLength)
+{
+ u16 temp = 1 + (wusbhc->ports_max / 8);
+ u8 length = 7 + 2 * temp;
+
+ if (wLength < length)
+ return -ENOSPC;
+ descr->bDescLength = 7 + 2 * temp;
+ descr->bDescriptorType = USB_DT_HUB; /* HUB type */
+ descr->bNbrPorts = wusbhc->ports_max;
+ descr->wHubCharacteristics = cpu_to_le16(
+ HUB_CHAR_COMMON_LPSM /* All ports power at once */
+ | 0x00 /* not part of compound device */
+ | HUB_CHAR_NO_OCPM /* No overcurrent protection */
+ | 0x00 /* 8 FS think time FIXME ?? */
+ | 0x00); /* No port indicators */
+ descr->bPwrOn2PwrGood = 0;
+ descr->bHubContrCurrent = 0;
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ memset(&descr->u.hs.DeviceRemovable[0], 0, temp);
+ memset(&descr->u.hs.DeviceRemovable[temp], 0xff, temp);
+ return 0;
+}
+
+/*
+ * Clear a hub feature
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Nothing to do, so no locking needed ;)
+ */
+static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature)
+{
+ int result;
+
+ switch (feature) {
+ case C_HUB_LOCAL_POWER:
+ /* FIXME: maybe plug bit 0 to the power input status,
+ * if any?
+ * see wusbhc_rh_get_hub_status() */
+ case C_HUB_OVER_CURRENT:
+ result = 0;
+ break;
+ default:
+ result = -EPIPE;
+ }
+ return result;
+}
+
+/*
+ * Return hub status (it is always zero...)
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Nothing to do, so no locking needed ;)
+ */
+static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf,
+ u16 wLength)
+{
+ /* FIXME: maybe plug bit 0 to the power input status (if any)? */
+ *buf = 0;
+ return 0;
+}
+
+/*
+ * Set a port feature
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature,
+ u8 selector, u8 port_idx)
+{
+ struct device *dev = wusbhc->dev;
+
+ if (port_idx > wusbhc->ports_max)
+ return -EINVAL;
+
+ switch (feature) {
+ /* According to USB2.0[11.24.2.13]p2, these features
+ * are not required to be implemented. */
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ case USB_PORT_FEAT_C_ENABLE:
+ case USB_PORT_FEAT_C_SUSPEND:
+ case USB_PORT_FEAT_C_CONNECTION:
+ case USB_PORT_FEAT_C_RESET:
+ return 0;
+ case USB_PORT_FEAT_POWER:
+ /* No such thing, but we fake it works */
+ mutex_lock(&wusbhc->mutex);
+ wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER;
+ mutex_unlock(&wusbhc->mutex);
+ return 0;
+ case USB_PORT_FEAT_RESET:
+ return wusbhc_rh_port_reset(wusbhc, port_idx);
+ case USB_PORT_FEAT_ENABLE:
+ case USB_PORT_FEAT_SUSPEND:
+ dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n",
+ port_idx, feature, selector);
+ return -ENOSYS;
+ default:
+ dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n",
+ port_idx, feature, selector);
+ return -EPIPE;
+ }
+
+ return 0;
+}
+
+/*
+ * Clear a port feature...
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
+ u8 selector, u8 port_idx)
+{
+ int result = 0;
+ struct device *dev = wusbhc->dev;
+
+ if (port_idx > wusbhc->ports_max)
+ return -EINVAL;
+
+ mutex_lock(&wusbhc->mutex);
+ switch (feature) {
+ case USB_PORT_FEAT_POWER: /* fake port always on */
+ /* According to USB2.0[11.24.2.7.1.4], no need to implement? */
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET;
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION;
+ break;
+ case USB_PORT_FEAT_ENABLE:
+ __wusbhc_dev_disable(wusbhc, port_idx);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE;
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ case USB_PORT_FEAT_C_SUSPEND:
+ dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n",
+ port_idx, feature, selector);
+ result = -ENOSYS;
+ break;
+ default:
+ dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n",
+ port_idx, feature, selector);
+ result = -EPIPE;
+ break;
+ }
+ mutex_unlock(&wusbhc->mutex);
+
+ return result;
+}
+
+/*
+ * Return the port's status
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx,
+ u32 *_buf, u16 wLength)
+{
+ __le16 *buf = (__le16 *)_buf;
+
+ if (port_idx > wusbhc->ports_max)
+ return -EINVAL;
+
+ mutex_lock(&wusbhc->mutex);
+ buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status);
+ buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change);
+ mutex_unlock(&wusbhc->mutex);
+
+ return 0;
+}
+
+/*
+ * Entry point for Root Hub operations
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ int result = -ENOSYS;
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+
+ switch (reqntype) {
+ case GetHubDescriptor:
+ result = wusbhc_rh_get_hub_descr(
+ wusbhc, wValue, wIndex,
+ (struct usb_hub_descriptor *) buf, wLength);
+ break;
+ case ClearHubFeature:
+ result = wusbhc_rh_clear_hub_feat(wusbhc, wValue);
+ break;
+ case GetHubStatus:
+ result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength);
+ break;
+
+ case SetPortFeature:
+ result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8,
+ (wIndex & 0xff) - 1);
+ break;
+ case ClearPortFeature:
+ result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8,
+ (wIndex & 0xff) - 1);
+ break;
+ case GetPortStatus:
+ result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1,
+ (u32 *)buf, wLength);
+ break;
+
+ case SetHubFeature:
+ default:
+ dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) "
+ "UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype,
+ wValue, wIndex, buf, wLength);
+ /* dump_stack(); */
+ result = -ENOSYS;
+ }
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_control);
+
+int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n",
+ __func__, usb_hcd, wusbhc, port_idx);
+ WARN_ON(1);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset);
+
+static void wusb_port_init(struct wusb_port *port)
+{
+ port->status |= USB_PORT_STAT_HIGH_SPEED;
+}
+
+/*
+ * Alloc fake port specific fields and status.
+ */
+int wusbhc_rh_create(struct wusbhc *wusbhc)
+{
+ int result = -ENOMEM;
+ size_t port_size, itr;
+ port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]);
+ wusbhc->port = kzalloc(port_size, GFP_KERNEL);
+ if (wusbhc->port == NULL)
+ goto error_port_alloc;
+ for (itr = 0; itr < wusbhc->ports_max; itr++)
+ wusb_port_init(&wusbhc->port[itr]);
+ result = 0;
+error_port_alloc:
+ return result;
+}
+
+void wusbhc_rh_destroy(struct wusbhc *wusbhc)
+{
+ kfree(wusbhc->port);
+}
diff --git a/drivers/staging/wusbcore/security.c b/drivers/staging/wusbcore/security.c
new file mode 100644
index 000000000000..14ac8c98ac9e
--- /dev/null
+++ b/drivers/staging/wusbcore/security.c
@@ -0,0 +1,599 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * Security support: encryption enablement, etc
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/usb/ch9.h>
+#include <linux/random.h>
+#include <linux/export.h>
+#include "wusbhc.h"
+#include <asm/unaligned.h>
+
+static void wusbhc_gtk_rekey_work(struct work_struct *work);
+
+int wusbhc_sec_create(struct wusbhc *wusbhc)
+{
+ /*
+ * WQ is singlethread because we need to serialize rekey operations.
+ * Use a separate workqueue for security operations instead of the
+ * wusbd workqueue because security operations may need to communicate
+ * directly with downstream wireless devices using synchronous URBs.
+ * If a device is not responding, this could block other host
+ * controller operations.
+ */
+ wusbhc->wq_security = create_singlethread_workqueue("wusbd_security");
+ if (wusbhc->wq_security == NULL) {
+ pr_err("WUSB-core: Cannot create wusbd_security workqueue\n");
+ return -ENOMEM;
+ }
+
+ wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) +
+ sizeof(wusbhc->gtk.data);
+ wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;
+ wusbhc->gtk.descr.bReserved = 0;
+ wusbhc->gtk_index = 0;
+
+ INIT_WORK(&wusbhc->gtk_rekey_work, wusbhc_gtk_rekey_work);
+
+ return 0;
+}
+
+
+/* Called when the HC is destroyed */
+void wusbhc_sec_destroy(struct wusbhc *wusbhc)
+{
+ destroy_workqueue(wusbhc->wq_security);
+}
+
+
+/**
+ * wusbhc_next_tkid - generate a new, currently unused, TKID
+ * @wusbhc: the WUSB host controller
+ * @wusb_dev: the device whose PTK the TKID is for
+ * (or NULL for a TKID for a GTK)
+ *
+ * The generated TKID consists of two parts: the device's authenticated
+ * address (or 0 or a GTK); and an incrementing number. This ensures
+ * that TKIDs cannot be shared between devices and by the time the
+ * incrementing number wraps around the older TKIDs will no longer be
+ * in use (a maximum of two keys may be active at any one time).
+ */
+static u32 wusbhc_next_tkid(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ u32 *tkid;
+ u32 addr;
+
+ if (wusb_dev == NULL) {
+ tkid = &wusbhc->gtk_tkid;
+ addr = 0;
+ } else {
+ tkid = &wusb_port_by_idx(wusbhc, wusb_dev->port_idx)->ptk_tkid;
+ addr = wusb_dev->addr & 0x7f;
+ }
+
+ *tkid = (addr << 8) | ((*tkid + 1) & 0xff);
+
+ return *tkid;
+}
+
+static void wusbhc_generate_gtk(struct wusbhc *wusbhc)
+{
+ const size_t key_size = sizeof(wusbhc->gtk.data);
+ u32 tkid;
+
+ tkid = wusbhc_next_tkid(wusbhc, NULL);
+
+ wusbhc->gtk.descr.tTKID[0] = (tkid >> 0) & 0xff;
+ wusbhc->gtk.descr.tTKID[1] = (tkid >> 8) & 0xff;
+ wusbhc->gtk.descr.tTKID[2] = (tkid >> 16) & 0xff;
+
+ get_random_bytes(wusbhc->gtk.descr.bKeyData, key_size);
+}
+
+/**
+ * wusbhc_sec_start - start the security management process
+ * @wusbhc: the WUSB host controller
+ *
+ * Generate and set an initial GTK on the host controller.
+ *
+ * Called when the HC is started.
+ */
+int wusbhc_sec_start(struct wusbhc *wusbhc)
+{
+ const size_t key_size = sizeof(wusbhc->gtk.data);
+ int result;
+
+ wusbhc_generate_gtk(wusbhc);
+
+ result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
+ &wusbhc->gtk.descr.bKeyData, key_size);
+ if (result < 0)
+ dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n",
+ result);
+
+ return result;
+}
+
+/**
+ * wusbhc_sec_stop - stop the security management process
+ * @wusbhc: the WUSB host controller
+ *
+ * Wait for any pending GTK rekeys to stop.
+ */
+void wusbhc_sec_stop(struct wusbhc *wusbhc)
+{
+ cancel_work_sync(&wusbhc->gtk_rekey_work);
+}
+
+
+/** @returns encryption type name */
+const char *wusb_et_name(u8 x)
+{
+ switch (x) {
+ case USB_ENC_TYPE_UNSECURE: return "unsecure";
+ case USB_ENC_TYPE_WIRED: return "wired";
+ case USB_ENC_TYPE_CCM_1: return "CCM-1";
+ case USB_ENC_TYPE_RSA_1: return "RSA-1";
+ default: return "unknown";
+ }
+}
+EXPORT_SYMBOL_GPL(wusb_et_name);
+
+/*
+ * Set the device encryption method
+ *
+ * We tell the device which encryption method to use; we do this when
+ * setting up the device's security.
+ */
+static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)
+{
+ int result;
+ struct device *dev = &usb_dev->dev;
+ struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
+
+ if (value) {
+ value = wusb_dev->ccm1_etd.bEncryptionValue;
+ } else {
+ /* FIXME: should be wusb_dev->etd[UNSECURE].bEncryptionValue */
+ value = 0;
+ }
+ /* Set device's */
+ result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_ENCRYPTION,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ value, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (result < 0)
+ dev_err(dev, "Can't set device's WUSB encryption to "
+ "%s (value %d): %d\n",
+ wusb_et_name(wusb_dev->ccm1_etd.bEncryptionType),
+ wusb_dev->ccm1_etd.bEncryptionValue, result);
+ return result;
+}
+
+/*
+ * Set the GTK to be used by a device.
+ *
+ * The device must be authenticated.
+ */
+static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ struct usb_device *usb_dev = wusb_dev->usb_dev;
+ u8 key_index = wusb_key_index(wusbhc->gtk_index,
+ WUSB_KEY_INDEX_TYPE_GTK, WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+ return usb_control_msg(
+ usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_DESCRIPTOR,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ USB_DT_KEY << 8 | key_index, 0,
+ &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
+ USB_CTRL_SET_TIMEOUT);
+}
+
+
+/* FIXME: prototype for adding security */
+int wusb_dev_sec_add(struct wusbhc *wusbhc,
+ struct usb_device *usb_dev, struct wusb_dev *wusb_dev)
+{
+ int result, bytes, secd_size;
+ struct device *dev = &usb_dev->dev;
+ struct usb_security_descriptor *secd, *new_secd;
+ const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
+ const void *itr, *top;
+ char buf[64];
+
+ secd = kmalloc(sizeof(*secd), GFP_KERNEL);
+ if (secd == NULL) {
+ result = -ENOMEM;
+ goto out;
+ }
+
+ result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
+ 0, secd, sizeof(*secd));
+ if (result < (int)sizeof(*secd)) {
+ dev_err(dev, "Can't read security descriptor or "
+ "not enough data: %d\n", result);
+ goto out;
+ }
+ secd_size = le16_to_cpu(secd->wTotalLength);
+ new_secd = krealloc(secd, secd_size, GFP_KERNEL);
+ if (new_secd == NULL) {
+ dev_err(dev,
+ "Can't allocate space for security descriptors\n");
+ result = -ENOMEM;
+ goto out;
+ }
+ secd = new_secd;
+ result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
+ 0, secd, secd_size);
+ if (result < secd_size) {
+ dev_err(dev, "Can't read security descriptor or "
+ "not enough data: %d\n", result);
+ goto out;
+ }
+ bytes = 0;
+ itr = &secd[1];
+ top = (void *)secd + result;
+ while (itr < top) {
+ etd = itr;
+ if (top - itr < sizeof(*etd)) {
+ dev_err(dev, "BUG: bad device security descriptor; "
+ "not enough data (%zu vs %zu bytes left)\n",
+ top - itr, sizeof(*etd));
+ break;
+ }
+ if (etd->bLength < sizeof(*etd)) {
+ dev_err(dev, "BUG: bad device encryption descriptor; "
+ "descriptor is too short "
+ "(%u vs %zu needed)\n",
+ etd->bLength, sizeof(*etd));
+ break;
+ }
+ itr += etd->bLength;
+ bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
+ "%s (0x%02x/%02x) ",
+ wusb_et_name(etd->bEncryptionType),
+ etd->bEncryptionValue, etd->bAuthKeyIndex);
+ if (etd->bEncryptionType == USB_ENC_TYPE_CCM_1)
+ ccm1_etd = etd;
+ }
+ /* This code only supports CCM1 as of now. */
+ /* FIXME: user has to choose which sec mode to use?
+ * In theory we want CCM */
+ if (ccm1_etd == NULL) {
+ dev_err(dev, "WUSB device doesn't support CCM1 encryption, "
+ "can't use!\n");
+ result = -EINVAL;
+ goto out;
+ }
+ wusb_dev->ccm1_etd = *ccm1_etd;
+ dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n",
+ buf, wusb_et_name(ccm1_etd->bEncryptionType),
+ ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex);
+ result = 0;
+out:
+ kfree(secd);
+ return result;
+}
+
+void wusb_dev_sec_rm(struct wusb_dev *wusb_dev)
+{
+ /* Nothing so far */
+}
+
+/**
+ * Update the address of an unauthenticated WUSB device
+ *
+ * Once we have successfully authenticated, we take it to addr0 state
+ * and then to a normal address.
+ *
+ * Before the device's address (as known by it) was usb_dev->devnum |
+ * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum.
+ */
+int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ int result = -ENOMEM;
+ struct usb_device *usb_dev = wusb_dev->usb_dev;
+ struct device *dev = &usb_dev->dev;
+ u8 new_address = wusb_dev->addr & 0x7F;
+
+ /* Set address 0 */
+ result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_ADDRESS,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "auth failed: can't set address 0: %d\n",
+ result);
+ goto error_addr0;
+ }
+ result = wusb_set_dev_addr(wusbhc, wusb_dev, 0);
+ if (result < 0)
+ goto error_addr0;
+ usb_set_device_state(usb_dev, USB_STATE_DEFAULT);
+ usb_ep0_reinit(usb_dev);
+
+ /* Set new (authenticated) address. */
+ result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_ADDRESS,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ new_address, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "auth failed: can't set address %u: %d\n",
+ new_address, result);
+ goto error_addr;
+ }
+ result = wusb_set_dev_addr(wusbhc, wusb_dev, new_address);
+ if (result < 0)
+ goto error_addr;
+ usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
+ usb_ep0_reinit(usb_dev);
+ usb_dev->authenticated = 1;
+error_addr:
+error_addr0:
+ return result;
+}
+
+/*
+ *
+ *
+ */
+/* FIXME: split and cleanup */
+int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
+ struct wusb_ckhdid *ck)
+{
+ int result = -ENOMEM;
+ struct usb_device *usb_dev = wusb_dev->usb_dev;
+ struct device *dev = &usb_dev->dev;
+ u32 tkid;
+ struct usb_handshake *hs;
+ struct aes_ccm_nonce ccm_n;
+ u8 mic[8];
+ struct wusb_keydvt_in keydvt_in;
+ struct wusb_keydvt_out keydvt_out;
+
+ hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL);
+ if (!hs)
+ goto error_kzalloc;
+
+ /* We need to turn encryption before beginning the 4way
+ * hshake (WUSB1.0[.3.2.2]) */
+ result = wusb_dev_set_encryption(usb_dev, 1);
+ if (result < 0)
+ goto error_dev_set_encryption;
+
+ tkid = wusbhc_next_tkid(wusbhc, wusb_dev);
+
+ hs[0].bMessageNumber = 1;
+ hs[0].bStatus = 0;
+ put_unaligned_le32(tkid, hs[0].tTKID);
+ hs[0].bReserved = 0;
+ memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID));
+ get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce));
+ memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */
+
+ result = usb_control_msg(
+ usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_HANDSHAKE,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 1, 0, &hs[0], sizeof(hs[0]), USB_CTRL_SET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "Handshake1: request failed: %d\n", result);
+ goto error_hs1;
+ }
+
+ /* Handshake 2, from the device -- need to verify fields */
+ result = usb_control_msg(
+ usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_GET_HANDSHAKE,
+ USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 2, 0, &hs[1], sizeof(hs[1]), USB_CTRL_GET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "Handshake2: request failed: %d\n", result);
+ goto error_hs2;
+ }
+
+ result = -EINVAL;
+ if (hs[1].bMessageNumber != 2) {
+ dev_err(dev, "Handshake2 failed: bad message number %u\n",
+ hs[1].bMessageNumber);
+ goto error_hs2;
+ }
+ if (hs[1].bStatus != 0) {
+ dev_err(dev, "Handshake2 failed: bad status %u\n",
+ hs[1].bStatus);
+ goto error_hs2;
+ }
+ if (memcmp(hs[0].tTKID, hs[1].tTKID, sizeof(hs[0].tTKID))) {
+ dev_err(dev, "Handshake2 failed: TKID mismatch "
+ "(#1 0x%02x%02x%02x vs #2 0x%02x%02x%02x)\n",
+ hs[0].tTKID[0], hs[0].tTKID[1], hs[0].tTKID[2],
+ hs[1].tTKID[0], hs[1].tTKID[1], hs[1].tTKID[2]);
+ goto error_hs2;
+ }
+ if (memcmp(hs[0].CDID, hs[1].CDID, sizeof(hs[0].CDID))) {
+ dev_err(dev, "Handshake2 failed: CDID mismatch\n");
+ goto error_hs2;
+ }
+
+ /* Setup the CCM nonce */
+ memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */
+ put_unaligned_le32(tkid, ccm_n.tkid);
+ ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr;
+ ccm_n.dest_addr.data[0] = wusb_dev->addr;
+ ccm_n.dest_addr.data[1] = 0;
+
+ /* Derive the KCK and PTK from CK, the CCM, H and D nonces */
+ memcpy(keydvt_in.hnonce, hs[0].nonce, sizeof(keydvt_in.hnonce));
+ memcpy(keydvt_in.dnonce, hs[1].nonce, sizeof(keydvt_in.dnonce));
+ result = wusb_key_derive(&keydvt_out, ck->data, &ccm_n, &keydvt_in);
+ if (result < 0) {
+ dev_err(dev, "Handshake2 failed: cannot derive keys: %d\n",
+ result);
+ goto error_hs2;
+ }
+
+ /* Compute MIC and verify it */
+ result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]);
+ if (result < 0) {
+ dev_err(dev, "Handshake2 failed: cannot compute MIC: %d\n",
+ result);
+ goto error_hs2;
+ }
+
+ if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) {
+ dev_err(dev, "Handshake2 failed: MIC mismatch\n");
+ goto error_hs2;
+ }
+
+ /* Send Handshake3 */
+ hs[2].bMessageNumber = 3;
+ hs[2].bStatus = 0;
+ put_unaligned_le32(tkid, hs[2].tTKID);
+ hs[2].bReserved = 0;
+ memcpy(hs[2].CDID, &wusb_dev->cdid, sizeof(hs[2].CDID));
+ memcpy(hs[2].nonce, hs[0].nonce, sizeof(hs[2].nonce));
+ result = wusb_oob_mic(hs[2].MIC, keydvt_out.kck, &ccm_n, &hs[2]);
+ if (result < 0) {
+ dev_err(dev, "Handshake3 failed: cannot compute MIC: %d\n",
+ result);
+ goto error_hs2;
+ }
+
+ result = usb_control_msg(
+ usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_HANDSHAKE,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 3, 0, &hs[2], sizeof(hs[2]), USB_CTRL_SET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "Handshake3: request failed: %d\n", result);
+ goto error_hs3;
+ }
+
+ result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid,
+ keydvt_out.ptk, sizeof(keydvt_out.ptk));
+ if (result < 0)
+ goto error_wusbhc_set_ptk;
+
+ result = wusb_dev_set_gtk(wusbhc, wusb_dev);
+ if (result < 0) {
+ dev_err(dev, "Set GTK for device: request failed: %d\n",
+ result);
+ goto error_wusbhc_set_gtk;
+ }
+
+ /* Update the device's address from unauth to auth */
+ if (usb_dev->authenticated == 0) {
+ result = wusb_dev_update_address(wusbhc, wusb_dev);
+ if (result < 0)
+ goto error_dev_update_address;
+ }
+ result = 0;
+ dev_info(dev, "device authenticated\n");
+
+error_dev_update_address:
+error_wusbhc_set_gtk:
+error_wusbhc_set_ptk:
+error_hs3:
+error_hs2:
+error_hs1:
+ memset(hs, 0, 3*sizeof(hs[0]));
+ memzero_explicit(&keydvt_out, sizeof(keydvt_out));
+ memzero_explicit(&keydvt_in, sizeof(keydvt_in));
+ memzero_explicit(&ccm_n, sizeof(ccm_n));
+ memzero_explicit(mic, sizeof(mic));
+ if (result < 0)
+ wusb_dev_set_encryption(usb_dev, 0);
+error_dev_set_encryption:
+ kfree(hs);
+error_kzalloc:
+ return result;
+}
+
+/*
+ * Once all connected and authenticated devices have received the new
+ * GTK, switch the host to using it.
+ */
+static void wusbhc_gtk_rekey_work(struct work_struct *work)
+{
+ struct wusbhc *wusbhc = container_of(work,
+ struct wusbhc, gtk_rekey_work);
+ size_t key_size = sizeof(wusbhc->gtk.data);
+ int port_idx;
+ struct wusb_dev *wusb_dev, *wusb_dev_next;
+ LIST_HEAD(rekey_list);
+
+ mutex_lock(&wusbhc->mutex);
+ /* generate the new key */
+ wusbhc_generate_gtk(wusbhc);
+ /* roll the gtk index. */
+ wusbhc->gtk_index = (wusbhc->gtk_index + 1) % (WUSB_KEY_INDEX_MAX + 1);
+ /*
+ * Save all connected devices on a list while holding wusbhc->mutex and
+ * take a reference to each one. Then submit the set key request to
+ * them after releasing the lock in order to avoid a deadlock.
+ */
+ for (port_idx = 0; port_idx < wusbhc->ports_max; port_idx++) {
+ wusb_dev = wusbhc->port[port_idx].wusb_dev;
+ if (!wusb_dev || !wusb_dev->usb_dev
+ || !wusb_dev->usb_dev->authenticated)
+ continue;
+
+ wusb_dev_get(wusb_dev);
+ list_add_tail(&wusb_dev->rekey_node, &rekey_list);
+ }
+ mutex_unlock(&wusbhc->mutex);
+
+ /* Submit the rekey requests without holding wusbhc->mutex. */
+ list_for_each_entry_safe(wusb_dev, wusb_dev_next, &rekey_list,
+ rekey_node) {
+ list_del_init(&wusb_dev->rekey_node);
+ dev_dbg(&wusb_dev->usb_dev->dev,
+ "%s: rekey device at port %d\n",
+ __func__, wusb_dev->port_idx);
+
+ if (wusb_dev_set_gtk(wusbhc, wusb_dev) < 0) {
+ dev_err(&wusb_dev->usb_dev->dev,
+ "%s: rekey device at port %d failed\n",
+ __func__, wusb_dev->port_idx);
+ }
+ wusb_dev_put(wusb_dev);
+ }
+
+ /* Switch the host controller to use the new GTK. */
+ mutex_lock(&wusbhc->mutex);
+ wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
+ &wusbhc->gtk.descr.bKeyData, key_size);
+ mutex_unlock(&wusbhc->mutex);
+}
+
+/**
+ * wusbhc_gtk_rekey - generate and distribute a new GTK
+ * @wusbhc: the WUSB host controller
+ *
+ * Generate a new GTK and distribute it to all connected and
+ * authenticated devices. When all devices have the new GTK, the host
+ * starts using it.
+ *
+ * This must be called after every device disconnect (see [WUSB]
+ * section 6.2.11.2).
+ */
+void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
+{
+ /*
+ * We need to submit a URB to the downstream WUSB devices in order to
+ * change the group key. This can't be done while holding the
+ * wusbhc->mutex since that is also taken in the urb_enqueue routine
+ * and will cause a deadlock. Instead, queue a work item to do
+ * it when the lock is not held
+ */
+ queue_work(wusbhc->wq_security, &wusbhc->gtk_rekey_work);
+}
diff --git a/drivers/staging/wusbcore/wa-hc.c b/drivers/staging/wusbcore/wa-hc.c
new file mode 100644
index 000000000000..6827075fb8a1
--- /dev/null
+++ b/drivers/staging/wusbcore/wa-hc.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wire Adapter Host Controller Driver
+ * Common items to HWA and DWA based HCDs
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "wusbhc.h"
+#include "wa-hc.h"
+
+/**
+ * Assumes
+ *
+ * wa->usb_dev and wa->usb_iface initialized and refcounted,
+ * wa->wa_descr initialized.
+ */
+int wa_create(struct wahc *wa, struct usb_interface *iface,
+ kernel_ulong_t quirks)
+{
+ int result;
+ struct device *dev = &iface->dev;
+
+ if (iface->cur_altsetting->desc.bNumEndpoints < 3)
+ return -ENODEV;
+
+ result = wa_rpipes_create(wa);
+ if (result < 0)
+ goto error_rpipes_create;
+ wa->quirks = quirks;
+ /* Fill up Data Transfer EP pointers */
+ wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;
+ wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
+ wa->dti_buf_size = usb_endpoint_maxp(wa->dti_epd);
+ wa->dti_buf = kmalloc(wa->dti_buf_size, GFP_KERNEL);
+ if (wa->dti_buf == NULL) {
+ result = -ENOMEM;
+ goto error_dti_buf_alloc;
+ }
+ result = wa_nep_create(wa, iface);
+ if (result < 0) {
+ dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n",
+ result);
+ goto error_nep_create;
+ }
+ return 0;
+
+error_nep_create:
+ kfree(wa->dti_buf);
+error_dti_buf_alloc:
+ wa_rpipes_destroy(wa);
+error_rpipes_create:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wa_create);
+
+
+void __wa_destroy(struct wahc *wa)
+{
+ if (wa->dti_urb) {
+ usb_kill_urb(wa->dti_urb);
+ usb_put_urb(wa->dti_urb);
+ }
+ kfree(wa->dti_buf);
+ wa_nep_destroy(wa);
+ wa_rpipes_destroy(wa);
+}
+EXPORT_SYMBOL_GPL(__wa_destroy);
+
+/**
+ * wa_reset_all - reset the WA device
+ * @wa: the WA to be reset
+ *
+ * For HWAs the radio controller and all other PALs are also reset.
+ */
+void wa_reset_all(struct wahc *wa)
+{
+ /* FIXME: assuming HWA. */
+ wusbhc_reset_all(wa->wusb);
+}
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB Wire Adapter core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/wa-hc.h b/drivers/staging/wusbcore/wa-hc.h
new file mode 100644
index 000000000000..5a38465724c2
--- /dev/null
+++ b/drivers/staging/wusbcore/wa-hc.h
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * HWA Host Controller Driver
+ * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8])
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This driver implements a USB Host Controller (struct usb_hcd) for a
+ * Wireless USB Host Controller based on the Wireless USB 1.0
+ * Host-Wire-Adapter specification (in layman terms, a USB-dongle that
+ * implements a Wireless USB host).
+ *
+ * Check out the Design-overview.txt file in the source documentation
+ * for other details on the implementation.
+ *
+ * Main blocks:
+ *
+ * driver glue with the driver API, workqueue daemon
+ *
+ * lc RC instance life cycle management (create, destroy...)
+ *
+ * hcd glue with the USB API Host Controller Interface API.
+ *
+ * nep Notification EndPoint management: collect notifications
+ * and queue them with the workqueue daemon.
+ *
+ * Handle notifications as coming from the NEP. Sends them
+ * off others to their respective modules (eg: connect,
+ * disconnect and reset go to devconnect).
+ *
+ * rpipe Remote Pipe management; rpipe is what we use to write
+ * to an endpoint on a WUSB device that is connected to a
+ * HWA RC.
+ *
+ * xfer Transfer management -- this is all the code that gets a
+ * buffer and pushes it to a device (or viceversa). *
+ *
+ * Some day a lot of this code will be shared between this driver and
+ * the drivers for DWA (xfer, rpipe).
+ *
+ * All starts at driver.c:hwahc_probe(), when one of this guys is
+ * connected. hwahc_disconnect() stops it.
+ *
+ * During operation, the main driver is devices connecting or
+ * disconnecting. They cause the HWA RC to send notifications into
+ * nep.c:hwahc_nep_cb() that will dispatch them to
+ * notif.c:wa_notif_dispatch(). From there they will fan to cause
+ * device connects, disconnects, etc.
+ *
+ * Note much of the activity is difficult to follow. For example a
+ * device connect goes to devconnect, which will cause the "fake" root
+ * hub port to show a connect and stop there. Then hub_wq will notice
+ * and call into the rh.c:hwahc_rc_port_reset() code to authenticate
+ * the device (and this might require user intervention) and enable
+ * the port.
+ *
+ * We also have a timer workqueue going from devconnect.c that
+ * schedules in hwahc_devconnect_create().
+ *
+ * The rest of the traffic is in the usual entry points of a USB HCD,
+ * which are hooked up in driver.c:hwahc_rc_driver, and defined in
+ * hcd.c.
+ */
+
+#ifndef __HWAHC_INTERNAL_H__
+#define __HWAHC_INTERNAL_H__
+
+#include <linux/completion.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include "../uwb/uwb.h"
+#include "include/wusb.h"
+#include "include/wusb-wa.h"
+
+struct wusbhc;
+struct wahc;
+extern void wa_urb_enqueue_run(struct work_struct *ws);
+extern void wa_process_errored_transfers_run(struct work_struct *ws);
+
+/**
+ * RPipe instance
+ *
+ * @descr's fields are kept in LE, as we need to send it back and
+ * forth.
+ *
+ * @wa is referenced when set
+ *
+ * @segs_available is the number of requests segments that still can
+ * be submitted to the controller without overloading
+ * it. It is initialized to descr->wRequests when
+ * aiming.
+ *
+ * A rpipe supports a max of descr->wRequests at the same time; before
+ * submitting seg_lock has to be taken. If segs_avail > 0, then we can
+ * submit; if not, we have to queue them.
+ */
+struct wa_rpipe {
+ struct kref refcnt;
+ struct usb_rpipe_descriptor descr;
+ struct usb_host_endpoint *ep;
+ struct wahc *wa;
+ spinlock_t seg_lock;
+ struct list_head seg_list;
+ struct list_head list_node;
+ atomic_t segs_available;
+ u8 buffer[1]; /* For reads/writes on USB */
+};
+
+
+enum wa_dti_state {
+ WA_DTI_TRANSFER_RESULT_PENDING,
+ WA_DTI_ISOC_PACKET_STATUS_PENDING,
+ WA_DTI_BUF_IN_DATA_PENDING
+};
+
+enum wa_quirks {
+ /*
+ * The Alereon HWA expects the data frames in isochronous transfer
+ * requests to be concatenated and not sent as separate packets.
+ */
+ WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC = 0x01,
+ /*
+ * The Alereon HWA can be instructed to not send transfer notifications
+ * as an optimization.
+ */
+ WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS = 0x02,
+};
+
+enum wa_vendor_specific_requests {
+ WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C,
+ WA_REQ_ALEREON_FEATURE_SET = 0x01,
+ WA_REQ_ALEREON_FEATURE_CLEAR = 0x00,
+};
+
+#define WA_MAX_BUF_IN_URBS 4
+/**
+ * Instance of a HWA Host Controller
+ *
+ * Except where a more specific lock/mutex applies or atomic, all
+ * fields protected by @mutex.
+ *
+ * @wa_descr Can be accessed without locking because it is in
+ * the same area where the device descriptors were
+ * read, so it is guaranteed to exist unmodified while
+ * the device exists.
+ *
+ * Endianess has been converted to CPU's.
+ *
+ * @nep_* can be accessed without locking as its processing is
+ * serialized; we submit a NEP URB and it comes to
+ * hwahc_nep_cb(), which won't issue another URB until it is
+ * done processing it.
+ *
+ * @xfer_list:
+ *
+ * List of active transfers to verify existence from a xfer id
+ * gotten from the xfer result message. Can't use urb->list because
+ * it goes by endpoint, and we don't know the endpoint at the time
+ * when we get the xfer result message. We can't really rely on the
+ * pointer (will have to change for 64 bits) as the xfer id is 32 bits.
+ *
+ * @xfer_delayed_list: List of transfers that need to be started
+ * (with a workqueue, because they were
+ * submitted from an atomic context).
+ *
+ * FIXME: this needs to be layered up: a wusbhc layer (for sharing
+ * commonalities with WHCI), a wa layer (for sharing
+ * commonalities with DWA-RC).
+ */
+struct wahc {
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+
+ /* HC to deliver notifications */
+ union {
+ struct wusbhc *wusb;
+ struct dwahc *dwa;
+ };
+
+ const struct usb_endpoint_descriptor *dto_epd, *dti_epd;
+ const struct usb_wa_descriptor *wa_descr;
+
+ struct urb *nep_urb; /* Notification EndPoint [lockless] */
+ struct edc nep_edc;
+ void *nep_buffer;
+ size_t nep_buffer_size;
+
+ atomic_t notifs_queued;
+
+ u16 rpipes;
+ unsigned long *rpipe_bm; /* rpipe usage bitmap */
+ struct list_head rpipe_delayed_list; /* delayed RPIPES. */
+ spinlock_t rpipe_lock; /* protect rpipe_bm and delayed list */
+ struct mutex rpipe_mutex; /* assigning resources to endpoints */
+
+ /*
+ * dti_state is used to track the state of the dti_urb. When dti_state
+ * is WA_DTI_ISOC_PACKET_STATUS_PENDING, dti_isoc_xfer_in_progress and
+ * dti_isoc_xfer_seg identify which xfer the incoming isoc packet
+ * status refers to.
+ */
+ enum wa_dti_state dti_state;
+ u32 dti_isoc_xfer_in_progress;
+ u8 dti_isoc_xfer_seg;
+ struct urb *dti_urb; /* URB for reading xfer results */
+ /* URBs for reading data in */
+ struct urb buf_in_urbs[WA_MAX_BUF_IN_URBS];
+ int active_buf_in_urbs; /* number of buf_in_urbs active. */
+ struct edc dti_edc; /* DTI error density counter */
+ void *dti_buf;
+ size_t dti_buf_size;
+
+ unsigned long dto_in_use; /* protect dto endoint serialization */
+
+ s32 status; /* For reading status */
+
+ struct list_head xfer_list;
+ struct list_head xfer_delayed_list;
+ struct list_head xfer_errored_list;
+ /*
+ * lock for the above xfer lists. Can be taken while a xfer->lock is
+ * held but not in the reverse order.
+ */
+ spinlock_t xfer_list_lock;
+ struct work_struct xfer_enqueue_work;
+ struct work_struct xfer_error_work;
+ atomic_t xfer_id_count;
+
+ kernel_ulong_t quirks;
+};
+
+
+extern int wa_create(struct wahc *wa, struct usb_interface *iface,
+ kernel_ulong_t);
+extern void __wa_destroy(struct wahc *wa);
+extern int wa_dti_start(struct wahc *wa);
+void wa_reset_all(struct wahc *wa);
+
+
+/* Miscellaneous constants */
+enum {
+ /** Max number of EPROTO errors we tolerate on the NEP in a
+ * period of time */
+ HWAHC_EPROTO_MAX = 16,
+ /** Period of time for EPROTO errors (in jiffies) */
+ HWAHC_EPROTO_PERIOD = 4 * HZ,
+};
+
+
+/* Notification endpoint handling */
+extern int wa_nep_create(struct wahc *, struct usb_interface *);
+extern void wa_nep_destroy(struct wahc *);
+
+static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask)
+{
+ struct urb *urb = wa->nep_urb;
+ urb->transfer_buffer = wa->nep_buffer;
+ urb->transfer_buffer_length = wa->nep_buffer_size;
+ return usb_submit_urb(urb, gfp_mask);
+}
+
+static inline void wa_nep_disarm(struct wahc *wa)
+{
+ usb_kill_urb(wa->nep_urb);
+}
+
+
+/* RPipes */
+static inline void wa_rpipe_init(struct wahc *wa)
+{
+ INIT_LIST_HEAD(&wa->rpipe_delayed_list);
+ spin_lock_init(&wa->rpipe_lock);
+ mutex_init(&wa->rpipe_mutex);
+}
+
+static inline void wa_init(struct wahc *wa)
+{
+ int index;
+
+ edc_init(&wa->nep_edc);
+ atomic_set(&wa->notifs_queued, 0);
+ wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
+ wa_rpipe_init(wa);
+ edc_init(&wa->dti_edc);
+ INIT_LIST_HEAD(&wa->xfer_list);
+ INIT_LIST_HEAD(&wa->xfer_delayed_list);
+ INIT_LIST_HEAD(&wa->xfer_errored_list);
+ spin_lock_init(&wa->xfer_list_lock);
+ INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run);
+ INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run);
+ wa->dto_in_use = 0;
+ atomic_set(&wa->xfer_id_count, 1);
+ /* init the buf in URBs */
+ for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index)
+ usb_init_urb(&(wa->buf_in_urbs[index]));
+ wa->active_buf_in_urbs = 0;
+}
+
+/**
+ * Destroy a pipe (when refcount drops to zero)
+ *
+ * Assumes it has been moved to the "QUIESCING" state.
+ */
+struct wa_xfer;
+extern void rpipe_destroy(struct kref *_rpipe);
+static inline
+void __rpipe_get(struct wa_rpipe *rpipe)
+{
+ kref_get(&rpipe->refcnt);
+}
+extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *,
+ struct urb *, gfp_t);
+static inline void rpipe_put(struct wa_rpipe *rpipe)
+{
+ kref_put(&rpipe->refcnt, rpipe_destroy);
+
+}
+extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *);
+extern void rpipe_clear_feature_stalled(struct wahc *,
+ struct usb_host_endpoint *);
+extern int wa_rpipes_create(struct wahc *);
+extern void wa_rpipes_destroy(struct wahc *);
+static inline void rpipe_avail_dec(struct wa_rpipe *rpipe)
+{
+ atomic_dec(&rpipe->segs_available);
+}
+
+/**
+ * Returns true if the rpipe is ready to submit more segments.
+ */
+static inline int rpipe_avail_inc(struct wa_rpipe *rpipe)
+{
+ return atomic_inc_return(&rpipe->segs_available) > 0
+ && !list_empty(&rpipe->seg_list);
+}
+
+
+/* Transferring data */
+extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *,
+ struct urb *, gfp_t);
+extern int wa_urb_dequeue(struct wahc *, struct urb *, int);
+extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *);
+
+
+/* Misc
+ *
+ * FIXME: Refcounting for the actual @hwahc object is not correct; I
+ * mean, this should be refcounting on the HCD underneath, but
+ * it is not. In any case, the semantics for HCD refcounting
+ * are *weird*...on refcount reaching zero it just frees
+ * it...no RC specific function is called...unless I miss
+ * something.
+ *
+ * FIXME: has to go away in favour of a 'struct' hcd based solution
+ */
+static inline struct wahc *wa_get(struct wahc *wa)
+{
+ usb_get_intf(wa->usb_iface);
+ return wa;
+}
+
+static inline void wa_put(struct wahc *wa)
+{
+ usb_put_intf(wa->usb_iface);
+}
+
+
+static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature)
+{
+ return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ feature,
+ wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+
+static inline int __wa_set_feature(struct wahc *wa, u16 feature)
+{
+ return __wa_feature(wa, 1, feature);
+}
+
+
+static inline int __wa_clear_feature(struct wahc *wa, u16 feature)
+{
+ return __wa_feature(wa, 0, feature);
+}
+
+
+/**
+ * Return the status of a Wire Adapter
+ *
+ * @wa: Wire Adapter instance
+ * @returns < 0 errno code on error, or status bitmap as described
+ * in WUSB1.0[8.3.1.6].
+ *
+ * NOTE: need malloc, some arches don't take USB from the stack
+ */
+static inline
+s32 __wa_get_status(struct wahc *wa)
+{
+ s32 result;
+ result = usb_control_msg(
+ wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+ USB_REQ_GET_STATUS,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ &wa->status, sizeof(wa->status), USB_CTRL_GET_TIMEOUT);
+ if (result >= 0)
+ result = wa->status;
+ return result;
+}
+
+
+/**
+ * Waits until the Wire Adapter's status matches @mask/@value
+ *
+ * @wa: Wire Adapter instance.
+ * @returns < 0 errno code on error, otherwise status.
+ *
+ * Loop until the WAs status matches the mask and value (status & mask
+ * == value). Timeout if it doesn't happen.
+ *
+ * FIXME: is there an official specification on how long status
+ * changes can take?
+ */
+static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value)
+{
+ s32 result;
+ unsigned loops = 10;
+ do {
+ msleep(50);
+ result = __wa_get_status(wa);
+ if ((result & mask) == value)
+ break;
+ if (loops-- == 0) {
+ result = -ETIMEDOUT;
+ break;
+ }
+ } while (result >= 0);
+ return result;
+}
+
+
+/** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */
+static inline int __wa_stop(struct wahc *wa)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+
+ result = __wa_clear_feature(wa, WA_ENABLE);
+ if (result < 0 && result != -ENODEV) {
+ dev_err(dev, "error commanding HC to stop: %d\n", result);
+ goto out;
+ }
+ result = __wa_wait_status(wa, WA_ENABLE, 0);
+ if (result < 0 && result != -ENODEV)
+ dev_err(dev, "error waiting for HC to stop: %d\n", result);
+out:
+ return 0;
+}
+
+
+#endif /* #ifndef __HWAHC_INTERNAL_H__ */
diff --git a/drivers/staging/wusbcore/wa-nep.c b/drivers/staging/wusbcore/wa-nep.c
new file mode 100644
index 000000000000..5f0656db5482
--- /dev/null
+++ b/drivers/staging/wusbcore/wa-nep.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * Notification EndPoint support
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This part takes care of getting the notification from the hw
+ * only and dispatching through wusbwad into
+ * wa_notif_dispatch. Handling is done there.
+ *
+ * WA notifications are limited in size; most of them are three or
+ * four bytes long, and the longest is the HWA Device Notification,
+ * which would not exceed 38 bytes (DNs are limited in payload to 32
+ * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA
+ * header (WUSB1.0[8.5.4.2]).
+ *
+ * It is not clear if more than one Device Notification can be packed
+ * in a HWA Notification, I assume no because of the wording in
+ * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could
+ * get is 256 bytes (as the bLength field is a byte).
+ *
+ * So what we do is we have this buffer and read into it; when a
+ * notification arrives we schedule work to a specific, single thread
+ * workqueue (so notifications are serialized) and copy the
+ * notification data. After scheduling the work, we rearm the read from
+ * the notification endpoint.
+ *
+ * Entry points here are:
+ *
+ * wa_nep_[create|destroy]() To initialize/release this subsystem
+ *
+ * wa_nep_cb() Callback for the notification
+ * endpoint; when data is ready, this
+ * does the dispatching.
+ */
+#include <linux/workqueue.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+
+#include "wa-hc.h"
+#include "wusbhc.h"
+
+/* Structure for queueing notifications to the workqueue */
+struct wa_notif_work {
+ struct work_struct work;
+ struct wahc *wa;
+ size_t size;
+ u8 data[];
+};
+
+/*
+ * Process incoming notifications from the WA's Notification EndPoint
+ * [the wuswad daemon, basically]
+ *
+ * @_nw: Pointer to a descriptor which has the pointer to the
+ * @wa, the size of the buffer and the work queue
+ * structure (so we can free all when done).
+ * @returns 0 if ok, < 0 errno code on error.
+ *
+ * All notifications follow the same format; they need to start with a
+ * 'struct wa_notif_hdr' header, so it is easy to parse through
+ * them. We just break the buffer in individual notifications (the
+ * standard doesn't say if it can be done or is forbidden, so we are
+ * cautious) and dispatch each.
+ *
+ * So the handling layers are is:
+ *
+ * WA specific notification (from NEP)
+ * Device Notification Received -> wa_handle_notif_dn()
+ * WUSB Device notification generic handling
+ * BPST Adjustment -> wa_handle_notif_bpst_adj()
+ * ... -> ...
+ *
+ * @wa has to be referenced
+ */
+static void wa_notif_dispatch(struct work_struct *ws)
+{
+ void *itr;
+ u8 missing = 0;
+ struct wa_notif_work *nw = container_of(ws, struct wa_notif_work,
+ work);
+ struct wahc *wa = nw->wa;
+ struct wa_notif_hdr *notif_hdr;
+ size_t size;
+
+ struct device *dev = &wa->usb_iface->dev;
+
+#if 0
+ /* FIXME: need to check for this??? */
+ if (usb_hcd->state == HC_STATE_QUIESCING) /* Going down? */
+ goto out; /* screw it */
+#endif
+ atomic_dec(&wa->notifs_queued); /* Throttling ctl */
+ size = nw->size;
+ itr = nw->data;
+
+ while (size) {
+ if (size < sizeof(*notif_hdr)) {
+ missing = sizeof(*notif_hdr) - size;
+ goto exhausted_buffer;
+ }
+ notif_hdr = itr;
+ if (size < notif_hdr->bLength)
+ goto exhausted_buffer;
+ itr += notif_hdr->bLength;
+ size -= notif_hdr->bLength;
+ /* Dispatch the notification [don't use itr or size!] */
+ switch (notif_hdr->bNotifyType) {
+ case HWA_NOTIF_DN: {
+ struct hwa_notif_dn *hwa_dn;
+ hwa_dn = container_of(notif_hdr, struct hwa_notif_dn,
+ hdr);
+ wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr,
+ hwa_dn->dndata,
+ notif_hdr->bLength - sizeof(*hwa_dn));
+ break;
+ }
+ case WA_NOTIF_TRANSFER:
+ wa_handle_notif_xfer(wa, notif_hdr);
+ break;
+ case HWA_NOTIF_BPST_ADJ:
+ break; /* no action needed for BPST ADJ. */
+ case DWA_NOTIF_RWAKE:
+ case DWA_NOTIF_PORTSTATUS:
+ /* FIXME: unimplemented WA NOTIFs */
+ /* fallthru */
+ default:
+ dev_err(dev, "HWA: unknown notification 0x%x, "
+ "%zu bytes; discarding\n",
+ notif_hdr->bNotifyType,
+ (size_t)notif_hdr->bLength);
+ break;
+ }
+ }
+out:
+ wa_put(wa);
+ kfree(nw);
+ return;
+
+ /* THIS SHOULD NOT HAPPEN
+ *
+ * Buffer exahusted with partial data remaining; just warn and
+ * discard the data, as this should not happen.
+ */
+exhausted_buffer:
+ dev_warn(dev, "HWA: device sent short notification, "
+ "%d bytes missing; discarding %d bytes.\n",
+ missing, (int)size);
+ goto out;
+}
+
+/*
+ * Deliver incoming WA notifications to the wusbwa workqueue
+ *
+ * @wa: Pointer the Wire Adapter Controller Data Streaming
+ * instance (part of an 'struct usb_hcd').
+ * @size: Size of the received buffer
+ * @returns 0 if ok, < 0 errno code on error.
+ *
+ * The input buffer is @wa->nep_buffer, with @size bytes
+ * (guaranteed to fit in the allocated space,
+ * @wa->nep_buffer_size).
+ */
+static int wa_nep_queue(struct wahc *wa, size_t size)
+{
+ int result = 0;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_notif_work *nw;
+
+ /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */
+ BUG_ON(size > wa->nep_buffer_size);
+ if (size == 0)
+ goto out;
+ if (atomic_read(&wa->notifs_queued) > 200) {
+ if (printk_ratelimit())
+ dev_err(dev, "Too many notifications queued, "
+ "throttling back\n");
+ goto out;
+ }
+ nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC);
+ if (nw == NULL) {
+ if (printk_ratelimit())
+ dev_err(dev, "No memory to queue notification\n");
+ result = -ENOMEM;
+ goto out;
+ }
+ INIT_WORK(&nw->work, wa_notif_dispatch);
+ nw->wa = wa_get(wa);
+ nw->size = size;
+ memcpy(nw->data, wa->nep_buffer, size);
+ atomic_inc(&wa->notifs_queued); /* Throttling ctl */
+ queue_work(wusbd, &nw->work);
+out:
+ /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */
+ return result;
+}
+
+/*
+ * Callback for the notification event endpoint
+ *
+ * Check's that everything is fine and then passes the data to be
+ * queued to the workqueue.
+ */
+static void wa_nep_cb(struct urb *urb)
+{
+ int result;
+ struct wahc *wa = urb->context;
+ struct device *dev = &wa->usb_iface->dev;
+
+ switch (result = urb->status) {
+ case 0:
+ result = wa_nep_queue(wa, urb->actual_length);
+ if (result < 0)
+ dev_err(dev, "NEP: unable to process notification(s): "
+ "%d\n", result);
+ break;
+ case -ECONNRESET: /* Not an error, but a controlled situation; */
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ case -ESHUTDOWN:
+ dev_dbg(dev, "NEP: going down %d\n", urb->status);
+ goto out;
+ default: /* On general errors, we retry unless it gets ugly */
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "NEP: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ goto out;
+ }
+ dev_err(dev, "NEP: URB error %d\n", urb->status);
+ }
+ result = wa_nep_arm(wa, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "NEP: cannot submit URB: %d\n", result);
+ wa_reset_all(wa);
+ }
+out:
+ return;
+}
+
+/*
+ * Initialize @wa's notification and event's endpoint stuff
+ *
+ * This includes the allocating the read buffer, the context ID
+ * allocation bitmap, the URB and submitting the URB.
+ */
+int wa_nep_create(struct wahc *wa, struct usb_interface *iface)
+{
+ int result;
+ struct usb_endpoint_descriptor *epd;
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+ struct device *dev = &iface->dev;
+
+ edc_init(&wa->nep_edc);
+ epd = &iface->cur_altsetting->endpoint[0].desc;
+ wa->nep_buffer_size = 1024;
+ wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL);
+ if (!wa->nep_buffer)
+ goto error_nep_buffer;
+ wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (wa->nep_urb == NULL)
+ goto error_urb_alloc;
+ usb_fill_int_urb(wa->nep_urb, usb_dev,
+ usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
+ wa->nep_buffer, wa->nep_buffer_size,
+ wa_nep_cb, wa, epd->bInterval);
+ result = wa_nep_arm(wa, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "Cannot submit notification URB: %d\n", result);
+ goto error_nep_arm;
+ }
+ return 0;
+
+error_nep_arm:
+ usb_free_urb(wa->nep_urb);
+error_urb_alloc:
+ kfree(wa->nep_buffer);
+error_nep_buffer:
+ return -ENOMEM;
+}
+
+void wa_nep_destroy(struct wahc *wa)
+{
+ wa_nep_disarm(wa);
+ usb_free_urb(wa->nep_urb);
+ kfree(wa->nep_buffer);
+}
diff --git a/drivers/staging/wusbcore/wa-rpipe.c b/drivers/staging/wusbcore/wa-rpipe.c
new file mode 100644
index 000000000000..a5734cbcd5ad
--- /dev/null
+++ b/drivers/staging/wusbcore/wa-rpipe.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter
+ * rpipe management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ *
+ * RPIPE
+ *
+ * Targeted at different downstream endpoints
+ *
+ * Descriptor: use to config the remote pipe.
+ *
+ * The number of blocks could be dynamic (wBlocks in descriptor is
+ * 0)--need to schedule them then.
+ *
+ * Each bit in wa->rpipe_bm represents if an rpipe is being used or
+ * not. Rpipes are represented with a 'struct wa_rpipe' that is
+ * attached to the hcpriv member of a 'struct usb_host_endpoint'.
+ *
+ * When you need to xfer data to an endpoint, you get an rpipe for it
+ * with wa_ep_rpipe_get(), which gives you a reference to the rpipe
+ * and keeps a single one (the first one) with the endpoint. When you
+ * are done transferring, you drop that reference. At the end the
+ * rpipe is always allocated and bound to the endpoint. There it might
+ * be recycled when not used.
+ *
+ * Addresses:
+ *
+ * We use a 1:1 mapping mechanism between port address (0 based
+ * index, actually) and the address. The USB stack knows about this.
+ *
+ * USB Stack port number 4 (1 based)
+ * WUSB code port index 3 (0 based)
+ * USB Address 5 (2 based -- 0 is for default, 1 for root hub)
+ *
+ * Now, because we don't use the concept as default address exactly
+ * like the (wired) USB code does, we need to kind of skip it. So we
+ * never take addresses from the urb->pipe, but from the
+ * urb->dev->devnum, to make sure that we always have the right
+ * destination address.
+ */
+#include <linux/atomic.h>
+#include <linux/bitmap.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "wusbhc.h"
+#include "wa-hc.h"
+
+static int __rpipe_get_descr(struct wahc *wa,
+ struct usb_rpipe_descriptor *descr, u16 index)
+{
+ ssize_t result;
+ struct device *dev = &wa->usb_iface->dev;
+
+ /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor()
+ * function because the arguments are different.
+ */
+ result = usb_control_msg(
+ wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
+ USB_CTRL_GET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "rpipe %u: get descriptor failed: %d\n",
+ index, (int)result);
+ goto error;
+ }
+ if (result < sizeof(*descr)) {
+ dev_err(dev, "rpipe %u: got short descriptor "
+ "(%zd vs %zd bytes needed)\n",
+ index, result, sizeof(*descr));
+ result = -EINVAL;
+ goto error;
+ }
+ result = 0;
+
+error:
+ return result;
+}
+
+/*
+ *
+ * The descriptor is assumed to be properly initialized (ie: you got
+ * it through __rpipe_get_descr()).
+ */
+static int __rpipe_set_descr(struct wahc *wa,
+ struct usb_rpipe_descriptor *descr, u16 index)
+{
+ ssize_t result;
+ struct device *dev = &wa->usb_iface->dev;
+
+ /* we cannot use the usb_get_descriptor() function because the
+ * arguments are different.
+ */
+ result = usb_control_msg(
+ wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_SET_DESCRIPTOR,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
+ USB_CTRL_SET_TIMEOUT);
+ if (result < 0) {
+ dev_err(dev, "rpipe %u: set descriptor failed: %d\n",
+ index, (int)result);
+ goto error;
+ }
+ if (result < sizeof(*descr)) {
+ dev_err(dev, "rpipe %u: sent short descriptor "
+ "(%zd vs %zd bytes required)\n",
+ index, result, sizeof(*descr));
+ result = -EINVAL;
+ goto error;
+ }
+ result = 0;
+
+error:
+ return result;
+
+}
+
+static void rpipe_init(struct wa_rpipe *rpipe)
+{
+ kref_init(&rpipe->refcnt);
+ spin_lock_init(&rpipe->seg_lock);
+ INIT_LIST_HEAD(&rpipe->seg_list);
+ INIT_LIST_HEAD(&rpipe->list_node);
+}
+
+static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wa->rpipe_lock, flags);
+ rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx);
+ if (rpipe_idx < wa->rpipes)
+ set_bit(rpipe_idx, wa->rpipe_bm);
+ spin_unlock_irqrestore(&wa->rpipe_lock, flags);
+
+ return rpipe_idx;
+}
+
+static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wa->rpipe_lock, flags);
+ clear_bit(rpipe_idx, wa->rpipe_bm);
+ spin_unlock_irqrestore(&wa->rpipe_lock, flags);
+}
+
+void rpipe_destroy(struct kref *_rpipe)
+{
+ struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt);
+ u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+ if (rpipe->ep)
+ rpipe->ep->hcpriv = NULL;
+ rpipe_put_idx(rpipe->wa, index);
+ wa_put(rpipe->wa);
+ kfree(rpipe);
+}
+EXPORT_SYMBOL_GPL(rpipe_destroy);
+
+/*
+ * Locate an idle rpipe, create an structure for it and return it
+ *
+ * @wa is referenced and unlocked
+ * @crs enum rpipe_attr, required endpoint characteristics
+ *
+ * The rpipe can be used only sequentially (not in parallel).
+ *
+ * The rpipe is moved into the "ready" state.
+ */
+static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs,
+ gfp_t gfp)
+{
+ int result;
+ unsigned rpipe_idx;
+ struct wa_rpipe *rpipe;
+ struct device *dev = &wa->usb_iface->dev;
+
+ rpipe = kzalloc(sizeof(*rpipe), gfp);
+ if (rpipe == NULL)
+ return -ENOMEM;
+ rpipe_init(rpipe);
+
+ /* Look for an idle pipe */
+ for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) {
+ rpipe_idx = rpipe_get_idx(wa, rpipe_idx);
+ if (rpipe_idx >= wa->rpipes) /* no more pipes :( */
+ break;
+ result = __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx);
+ if (result < 0)
+ dev_err(dev, "Can't get descriptor for rpipe %u: %d\n",
+ rpipe_idx, result);
+ else if ((rpipe->descr.bmCharacteristics & crs) != 0)
+ goto found;
+ rpipe_put_idx(wa, rpipe_idx);
+ }
+ *prpipe = NULL;
+ kfree(rpipe);
+ return -ENXIO;
+
+found:
+ set_bit(rpipe_idx, wa->rpipe_bm);
+ rpipe->wa = wa_get(wa);
+ *prpipe = rpipe;
+ return 0;
+}
+
+static int __rpipe_reset(struct wahc *wa, unsigned index)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+
+ result = usb_control_msg(
+ wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_RPIPE_RESET,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ 0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (result < 0)
+ dev_err(dev, "rpipe %u: reset failed: %d\n",
+ index, result);
+ return result;
+}
+
+/*
+ * Fake companion descriptor for ep0
+ *
+ * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl
+ */
+static struct usb_wireless_ep_comp_descriptor epc0 = {
+ .bLength = sizeof(epc0),
+ .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP,
+ .bMaxBurst = 1,
+ .bMaxSequence = 2,
+};
+
+/*
+ * Look for EP companion descriptor
+ *
+ * Get there, look for Inara in the endpoint's extra descriptors
+ */
+static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find(
+ struct device *dev, struct usb_host_endpoint *ep)
+{
+ void *itr;
+ size_t itr_size;
+ struct usb_descriptor_header *hdr;
+ struct usb_wireless_ep_comp_descriptor *epcd;
+
+ if (ep->desc.bEndpointAddress == 0) {
+ epcd = &epc0;
+ goto out;
+ }
+ itr = ep->extra;
+ itr_size = ep->extralen;
+ epcd = NULL;
+ while (itr_size > 0) {
+ if (itr_size < sizeof(*hdr)) {
+ dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors "
+ "at offset %zu: only %zu bytes left\n",
+ ep->desc.bEndpointAddress,
+ itr - (void *) ep->extra, itr_size);
+ break;
+ }
+ hdr = itr;
+ if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) {
+ epcd = itr;
+ break;
+ }
+ if (hdr->bLength > itr_size) {
+ dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor "
+ "at offset %zu (type 0x%02x) "
+ "length %d but only %zu bytes left\n",
+ ep->desc.bEndpointAddress,
+ itr - (void *) ep->extra, hdr->bDescriptorType,
+ hdr->bLength, itr_size);
+ break;
+ }
+ itr += hdr->bLength;
+ itr_size -= hdr->bLength;
+ }
+out:
+ return epcd;
+}
+
+/*
+ * Aim an rpipe to its device & endpoint destination
+ *
+ * Make sure we change the address to unauthenticated if the device
+ * is WUSB and it is not authenticated.
+ */
+static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,
+ struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp)
+{
+ int result = -ENOMSG; /* better code for lack of companion? */
+ struct device *dev = &wa->usb_iface->dev;
+ struct usb_device *usb_dev = urb->dev;
+ struct usb_wireless_ep_comp_descriptor *epcd;
+ u32 ack_window, epcd_max_sequence;
+ u8 unauth;
+
+ epcd = rpipe_epc_find(dev, ep);
+ if (epcd == NULL) {
+ dev_err(dev, "ep 0x%02x: can't find companion descriptor\n",
+ ep->desc.bEndpointAddress);
+ goto error;
+ }
+ unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0;
+ __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex));
+ atomic_set(&rpipe->segs_available,
+ le16_to_cpu(rpipe->descr.wRequests));
+ /* FIXME: block allocation system; request with queuing and timeout */
+ /* FIXME: compute so seg_size > ep->maxpktsize */
+ rpipe->descr.wBlocks = cpu_to_le16(16); /* given */
+ /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */
+ if (usb_endpoint_xfer_isoc(&ep->desc))
+ rpipe->descr.wMaxPacketSize = epcd->wOverTheAirPacketSize;
+ else
+ rpipe->descr.wMaxPacketSize = ep->desc.wMaxPacketSize;
+
+ rpipe->descr.hwa_bMaxBurst = max(min_t(unsigned int,
+ epcd->bMaxBurst, 16U), 1U);
+ rpipe->descr.hwa_bDeviceInfoIndex =
+ wusb_port_no_to_idx(urb->dev->portnum);
+ /* FIXME: use maximum speed as supported or recommended by device */
+ rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ?
+ UWB_PHY_RATE_53 : UWB_PHY_RATE_200;
+
+ dev_dbg(dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n",
+ urb->dev->devnum, urb->dev->devnum | unauth,
+ le16_to_cpu(rpipe->descr.wRPipeIndex),
+ usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed);
+
+ rpipe->descr.hwa_reserved = 0;
+
+ rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress;
+ /* FIXME: bDataSequence */
+ rpipe->descr.bDataSequence = 0;
+
+ /* start with base window of hwa_bMaxBurst bits starting at 0. */
+ ack_window = 0xFFFFFFFF >> (32 - rpipe->descr.hwa_bMaxBurst);
+ rpipe->descr.dwCurrentWindow = cpu_to_le32(ack_window);
+ epcd_max_sequence = max(min_t(unsigned int,
+ epcd->bMaxSequence, 32U), 2U);
+ rpipe->descr.bMaxDataSequence = epcd_max_sequence - 1;
+ rpipe->descr.bInterval = ep->desc.bInterval;
+ if (usb_endpoint_xfer_isoc(&ep->desc))
+ rpipe->descr.bOverTheAirInterval = epcd->bOverTheAirInterval;
+ else
+ rpipe->descr.bOverTheAirInterval = 0; /* 0 if not isoc */
+ /* FIXME: xmit power & preamble blah blah */
+ rpipe->descr.bmAttribute = (ep->desc.bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK);
+ /* rpipe->descr.bmCharacteristics RO */
+ rpipe->descr.bmRetryOptions = (wa->wusb->retry_count & 0xF);
+ /* FIXME: use for assessing link quality? */
+ rpipe->descr.wNumTransactionErrors = 0;
+ result = __rpipe_set_descr(wa, &rpipe->descr,
+ le16_to_cpu(rpipe->descr.wRPipeIndex));
+ if (result < 0) {
+ dev_err(dev, "Cannot aim rpipe: %d\n", result);
+ goto error;
+ }
+ result = 0;
+error:
+ return result;
+}
+
+/*
+ * Check an aimed rpipe to make sure it points to where we want
+ *
+ * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth
+ * space; when it is like that, we or 0x80 to make an unauth address.
+ */
+static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa,
+ const struct usb_host_endpoint *ep,
+ const struct urb *urb, gfp_t gfp)
+{
+ int result = 0;
+ struct device *dev = &wa->usb_iface->dev;
+ u8 portnum = wusb_port_no_to_idx(urb->dev->portnum);
+
+#define AIM_CHECK(rdf, val, text) \
+ do { \
+ if (rpipe->descr.rdf != (val)) { \
+ dev_err(dev, \
+ "rpipe aim discrepancy: " #rdf " " text "\n", \
+ rpipe->descr.rdf, (val)); \
+ result = -EINVAL; \
+ WARN_ON(1); \
+ } \
+ } while (0)
+ AIM_CHECK(hwa_bDeviceInfoIndex, portnum, "(%u vs %u)");
+ AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ?
+ UWB_PHY_RATE_53 : UWB_PHY_RATE_200,
+ "(%u vs %u)");
+ AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)");
+ AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)");
+ AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)");
+#undef AIM_CHECK
+ return result;
+}
+
+#ifndef CONFIG_BUG
+#define CONFIG_BUG 0
+#endif
+
+/*
+ * Make sure there is an rpipe allocated for an endpoint
+ *
+ * If already allocated, we just refcount it; if not, we get an
+ * idle one, aim it to the right location and take it.
+ *
+ * Attaches to ep->hcpriv and rpipe->ep to ep.
+ */
+int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep,
+ struct urb *urb, gfp_t gfp)
+{
+ int result = 0;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_rpipe *rpipe;
+ u8 eptype;
+
+ mutex_lock(&wa->rpipe_mutex);
+ rpipe = ep->hcpriv;
+ if (rpipe != NULL) {
+ if (CONFIG_BUG == 1) {
+ result = rpipe_check_aim(rpipe, wa, ep, urb, gfp);
+ if (result < 0)
+ goto error;
+ }
+ __rpipe_get(rpipe);
+ dev_dbg(dev, "ep 0x%02x: reusing rpipe %u\n",
+ ep->desc.bEndpointAddress,
+ le16_to_cpu(rpipe->descr.wRPipeIndex));
+ } else {
+ /* hmm, assign idle rpipe, aim it */
+ result = -ENOBUFS;
+ eptype = ep->desc.bmAttributes & 0x03;
+ result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp);
+ if (result < 0)
+ goto error;
+ result = rpipe_aim(rpipe, wa, ep, urb, gfp);
+ if (result < 0) {
+ rpipe_put(rpipe);
+ goto error;
+ }
+ ep->hcpriv = rpipe;
+ rpipe->ep = ep;
+ __rpipe_get(rpipe); /* for caching into ep->hcpriv */
+ dev_dbg(dev, "ep 0x%02x: using rpipe %u\n",
+ ep->desc.bEndpointAddress,
+ le16_to_cpu(rpipe->descr.wRPipeIndex));
+ }
+error:
+ mutex_unlock(&wa->rpipe_mutex);
+ return result;
+}
+
+/*
+ * Allocate the bitmap for each rpipe.
+ */
+int wa_rpipes_create(struct wahc *wa)
+{
+ wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes);
+ wa->rpipe_bm = bitmap_zalloc(wa->rpipes, GFP_KERNEL);
+ if (wa->rpipe_bm == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+void wa_rpipes_destroy(struct wahc *wa)
+{
+ struct device *dev = &wa->usb_iface->dev;
+
+ if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) {
+ WARN_ON(1);
+ dev_err(dev, "BUG: pipes not released on exit: %*pb\n",
+ wa->rpipes, wa->rpipe_bm);
+ }
+ bitmap_free(wa->rpipe_bm);
+}
+
+/*
+ * Release resources allocated for an endpoint
+ *
+ * If there is an associated rpipe to this endpoint, Abort any pending
+ * transfers and put it. If the rpipe ends up being destroyed,
+ * __rpipe_destroy() will cleanup ep->hcpriv.
+ *
+ * This is called before calling hcd->stop(), so you don't need to do
+ * anything else in there.
+ */
+void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep)
+{
+ struct wa_rpipe *rpipe;
+
+ mutex_lock(&wa->rpipe_mutex);
+ rpipe = ep->hcpriv;
+ if (rpipe != NULL) {
+ u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+ usb_control_msg(
+ wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_RPIPE_ABORT,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ 0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ rpipe_put(rpipe);
+ }
+ mutex_unlock(&wa->rpipe_mutex);
+}
+EXPORT_SYMBOL_GPL(rpipe_ep_disable);
+
+/* Clear the stalled status of an RPIPE. */
+void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep)
+{
+ struct wa_rpipe *rpipe;
+
+ mutex_lock(&wa->rpipe_mutex);
+ rpipe = ep->hcpriv;
+ if (rpipe != NULL) {
+ u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+ usb_control_msg(
+ wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ RPIPE_STALL, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ }
+ mutex_unlock(&wa->rpipe_mutex);
+}
+EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled);
diff --git a/drivers/staging/wusbcore/wa-xfer.c b/drivers/staging/wusbcore/wa-xfer.c
new file mode 100644
index 000000000000..abf88cea37bb
--- /dev/null
+++ b/drivers/staging/wusbcore/wa-xfer.c
@@ -0,0 +1,2927 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter
+ * Data transfer and URB enqueing
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * How transfers work: get a buffer, break it up in segments (segment
+ * size is a multiple of the maxpacket size). For each segment issue a
+ * segment request (struct wa_xfer_*), then send the data buffer if
+ * out or nothing if in (all over the DTO endpoint).
+ *
+ * For each submitted segment request, a notification will come over
+ * the NEP endpoint and a transfer result (struct xfer_result) will
+ * arrive in the DTI URB. Read it, get the xfer ID, see if there is
+ * data coming (inbound transfer), schedule a read and handle it.
+ *
+ * Sounds simple, it is a pain to implement.
+ *
+ *
+ * ENTRY POINTS
+ *
+ * FIXME
+ *
+ * LIFE CYCLE / STATE DIAGRAM
+ *
+ * FIXME
+ *
+ * THIS CODE IS DISGUSTING
+ *
+ * Warned you are; it's my second try and still not happy with it.
+ *
+ * NOTES:
+ *
+ * - No iso
+ *
+ * - Supports DMA xfers, control, bulk and maybe interrupt
+ *
+ * - Does not recycle unused rpipes
+ *
+ * An rpipe is assigned to an endpoint the first time it is used,
+ * and then it's there, assigned, until the endpoint is disabled
+ * (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the
+ * rpipe to the endpoint is done under the wa->rpipe_sem semaphore
+ * (should be a mutex).
+ *
+ * Two methods it could be done:
+ *
+ * (a) set up a timer every time an rpipe's use count drops to 1
+ * (which means unused) or when a transfer ends. Reset the
+ * timer when a xfer is queued. If the timer expires, release
+ * the rpipe [see rpipe_ep_disable()].
+ *
+ * (b) when looking for free rpipes to attach [rpipe_get_by_ep()],
+ * when none are found go over the list, check their endpoint
+ * and their activity record (if no last-xfer-done-ts in the
+ * last x seconds) take it
+ *
+ * However, due to the fact that we have a set of limited
+ * resources (max-segments-at-the-same-time per xfer,
+ * xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end
+ * we are going to have to rebuild all this based on an scheduler,
+ * to where we have a list of transactions to do and based on the
+ * availability of the different required components (blocks,
+ * rpipes, segment slots, etc), we go scheduling them. Painful.
+ */
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/hash.h>
+#include <linux/ratelimit.h>
+#include <linux/export.h>
+#include <linux/scatterlist.h>
+
+#include "wa-hc.h"
+#include "wusbhc.h"
+
+enum {
+ /* [WUSB] section 8.3.3 allocates 7 bits for the segment index. */
+ WA_SEGS_MAX = 128,
+};
+
+enum wa_seg_status {
+ WA_SEG_NOTREADY,
+ WA_SEG_READY,
+ WA_SEG_DELAYED,
+ WA_SEG_SUBMITTED,
+ WA_SEG_PENDING,
+ WA_SEG_DTI_PENDING,
+ WA_SEG_DONE,
+ WA_SEG_ERROR,
+ WA_SEG_ABORTED,
+};
+
+static void wa_xfer_delayed_run(struct wa_rpipe *);
+static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting);
+
+/*
+ * Life cycle governed by 'struct urb' (the refcount of the struct is
+ * that of the 'struct urb' and usb_free_urb() would free the whole
+ * struct).
+ */
+struct wa_seg {
+ struct urb tr_urb; /* transfer request urb. */
+ struct urb *isoc_pack_desc_urb; /* for isoc packet descriptor. */
+ struct urb *dto_urb; /* for data output. */
+ struct list_head list_node; /* for rpipe->req_list */
+ struct wa_xfer *xfer; /* out xfer */
+ u8 index; /* which segment we are */
+ int isoc_frame_count; /* number of isoc frames in this segment. */
+ int isoc_frame_offset; /* starting frame offset in the xfer URB. */
+ /* Isoc frame that the current transfer buffer corresponds to. */
+ int isoc_frame_index;
+ int isoc_size; /* size of all isoc frames sent by this seg. */
+ enum wa_seg_status status;
+ ssize_t result; /* bytes xfered or error */
+ struct wa_xfer_hdr xfer_hdr;
+};
+
+static inline void wa_seg_init(struct wa_seg *seg)
+{
+ usb_init_urb(&seg->tr_urb);
+
+ /* set the remaining memory to 0. */
+ memset(((void *)seg) + sizeof(seg->tr_urb), 0,
+ sizeof(*seg) - sizeof(seg->tr_urb));
+}
+
+/*
+ * Protected by xfer->lock
+ *
+ */
+struct wa_xfer {
+ struct kref refcnt;
+ struct list_head list_node;
+ spinlock_t lock;
+ u32 id;
+
+ struct wahc *wa; /* Wire adapter we are plugged to */
+ struct usb_host_endpoint *ep;
+ struct urb *urb; /* URB we are transferring for */
+ struct wa_seg **seg; /* transfer segments */
+ u8 segs, segs_submitted, segs_done;
+ unsigned is_inbound:1;
+ unsigned is_dma:1;
+ size_t seg_size;
+ int result;
+
+ gfp_t gfp; /* allocation mask */
+
+ struct wusb_dev *wusb_dev; /* for activity timestamps */
+};
+
+static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
+ struct wa_seg *seg, int curr_iso_frame);
+static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
+ int starting_index, enum wa_seg_status status);
+
+static inline void wa_xfer_init(struct wa_xfer *xfer)
+{
+ kref_init(&xfer->refcnt);
+ INIT_LIST_HEAD(&xfer->list_node);
+ spin_lock_init(&xfer->lock);
+}
+
+/*
+ * Destroy a transfer structure
+ *
+ * Note that freeing xfer->seg[cnt]->tr_urb will free the containing
+ * xfer->seg[cnt] memory that was allocated by __wa_xfer_setup_segs.
+ */
+static void wa_xfer_destroy(struct kref *_xfer)
+{
+ struct wa_xfer *xfer = container_of(_xfer, struct wa_xfer, refcnt);
+ if (xfer->seg) {
+ unsigned cnt;
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ struct wa_seg *seg = xfer->seg[cnt];
+ if (seg) {
+ usb_free_urb(seg->isoc_pack_desc_urb);
+ if (seg->dto_urb) {
+ kfree(seg->dto_urb->sg);
+ usb_free_urb(seg->dto_urb);
+ }
+ usb_free_urb(&seg->tr_urb);
+ }
+ }
+ kfree(xfer->seg);
+ }
+ kfree(xfer);
+}
+
+static void wa_xfer_get(struct wa_xfer *xfer)
+{
+ kref_get(&xfer->refcnt);
+}
+
+static void wa_xfer_put(struct wa_xfer *xfer)
+{
+ kref_put(&xfer->refcnt, wa_xfer_destroy);
+}
+
+/*
+ * Try to get exclusive access to the DTO endpoint resource. Return true
+ * if successful.
+ */
+static inline int __wa_dto_try_get(struct wahc *wa)
+{
+ return (test_and_set_bit(0, &wa->dto_in_use) == 0);
+}
+
+/* Release the DTO endpoint resource. */
+static inline void __wa_dto_put(struct wahc *wa)
+{
+ clear_bit_unlock(0, &wa->dto_in_use);
+}
+
+/* Service RPIPEs that are waiting on the DTO resource. */
+static void wa_check_for_delayed_rpipes(struct wahc *wa)
+{
+ unsigned long flags;
+ int dto_waiting = 0;
+ struct wa_rpipe *rpipe;
+
+ spin_lock_irqsave(&wa->rpipe_lock, flags);
+ while (!list_empty(&wa->rpipe_delayed_list) && !dto_waiting) {
+ rpipe = list_first_entry(&wa->rpipe_delayed_list,
+ struct wa_rpipe, list_node);
+ __wa_xfer_delayed_run(rpipe, &dto_waiting);
+ /* remove this RPIPE from the list if it is not waiting. */
+ if (!dto_waiting) {
+ pr_debug("%s: RPIPE %d serviced and removed from delayed list.\n",
+ __func__,
+ le16_to_cpu(rpipe->descr.wRPipeIndex));
+ list_del_init(&rpipe->list_node);
+ }
+ }
+ spin_unlock_irqrestore(&wa->rpipe_lock, flags);
+}
+
+/* add this RPIPE to the end of the delayed RPIPE list. */
+static void wa_add_delayed_rpipe(struct wahc *wa, struct wa_rpipe *rpipe)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wa->rpipe_lock, flags);
+ /* add rpipe to the list if it is not already on it. */
+ if (list_empty(&rpipe->list_node)) {
+ pr_debug("%s: adding RPIPE %d to the delayed list.\n",
+ __func__, le16_to_cpu(rpipe->descr.wRPipeIndex));
+ list_add_tail(&rpipe->list_node, &wa->rpipe_delayed_list);
+ }
+ spin_unlock_irqrestore(&wa->rpipe_lock, flags);
+}
+
+/*
+ * xfer is referenced
+ *
+ * xfer->lock has to be unlocked
+ *
+ * We take xfer->lock for setting the result; this is a barrier
+ * against drivers/usb/core/hcd.c:unlink1() being called after we call
+ * usb_hcd_giveback_urb() and wa_urb_dequeue() trying to get a
+ * reference to the transfer.
+ */
+static void wa_xfer_giveback(struct wa_xfer *xfer)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags);
+ list_del_init(&xfer->list_node);
+ usb_hcd_unlink_urb_from_ep(&(xfer->wa->wusb->usb_hcd), xfer->urb);
+ spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags);
+ /* FIXME: segmentation broken -- kills DWA */
+ wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result);
+ wa_put(xfer->wa);
+ wa_xfer_put(xfer);
+}
+
+/*
+ * xfer is referenced
+ *
+ * xfer->lock has to be unlocked
+ */
+static void wa_xfer_completion(struct wa_xfer *xfer)
+{
+ if (xfer->wusb_dev)
+ wusb_dev_put(xfer->wusb_dev);
+ rpipe_put(xfer->ep->hcpriv);
+ wa_xfer_giveback(xfer);
+}
+
+/*
+ * Initialize a transfer's ID
+ *
+ * We need to use a sequential number; if we use the pointer or the
+ * hash of the pointer, it can repeat over sequential transfers and
+ * then it will confuse the HWA....wonder why in hell they put a 32
+ * bit handle in there then.
+ */
+static void wa_xfer_id_init(struct wa_xfer *xfer)
+{
+ xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count);
+}
+
+/* Return the xfer's ID. */
+static inline u32 wa_xfer_id(struct wa_xfer *xfer)
+{
+ return xfer->id;
+}
+
+/* Return the xfer's ID in transport format (little endian). */
+static inline __le32 wa_xfer_id_le32(struct wa_xfer *xfer)
+{
+ return cpu_to_le32(xfer->id);
+}
+
+/*
+ * If transfer is done, wrap it up and return true
+ *
+ * xfer->lock has to be locked
+ */
+static unsigned __wa_xfer_is_done(struct wa_xfer *xfer)
+{
+ struct device *dev = &xfer->wa->usb_iface->dev;
+ unsigned result, cnt;
+ struct wa_seg *seg;
+ struct urb *urb = xfer->urb;
+ unsigned found_short = 0;
+
+ result = xfer->segs_done == xfer->segs_submitted;
+ if (result == 0)
+ goto out;
+ urb->actual_length = 0;
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ seg = xfer->seg[cnt];
+ switch (seg->status) {
+ case WA_SEG_DONE:
+ if (found_short && seg->result > 0) {
+ dev_dbg(dev, "xfer %p ID %08X#%u: bad short segments (%zu)\n",
+ xfer, wa_xfer_id(xfer), cnt,
+ seg->result);
+ urb->status = -EINVAL;
+ goto out;
+ }
+ urb->actual_length += seg->result;
+ if (!(usb_pipeisoc(xfer->urb->pipe))
+ && seg->result < xfer->seg_size
+ && cnt != xfer->segs-1)
+ found_short = 1;
+ dev_dbg(dev, "xfer %p ID %08X#%u: DONE short %d "
+ "result %zu urb->actual_length %d\n",
+ xfer, wa_xfer_id(xfer), seg->index, found_short,
+ seg->result, urb->actual_length);
+ break;
+ case WA_SEG_ERROR:
+ xfer->result = seg->result;
+ dev_dbg(dev, "xfer %p ID %08X#%u: ERROR result %zi(0x%08zX)\n",
+ xfer, wa_xfer_id(xfer), seg->index, seg->result,
+ seg->result);
+ goto out;
+ case WA_SEG_ABORTED:
+ xfer->result = seg->result;
+ dev_dbg(dev, "xfer %p ID %08X#%u: ABORTED result %zi(0x%08zX)\n",
+ xfer, wa_xfer_id(xfer), seg->index, seg->result,
+ seg->result);
+ goto out;
+ default:
+ dev_warn(dev, "xfer %p ID %08X#%u: is_done bad state %d\n",
+ xfer, wa_xfer_id(xfer), cnt, seg->status);
+ xfer->result = -EINVAL;
+ goto out;
+ }
+ }
+ xfer->result = 0;
+out:
+ return result;
+}
+
+/*
+ * Mark the given segment as done. Return true if this completes the xfer.
+ * This should only be called for segs that have been submitted to an RPIPE.
+ * Delayed segs are not marked as submitted so they do not need to be marked
+ * as done when cleaning up.
+ *
+ * xfer->lock has to be locked
+ */
+static unsigned __wa_xfer_mark_seg_as_done(struct wa_xfer *xfer,
+ struct wa_seg *seg, enum wa_seg_status status)
+{
+ seg->status = status;
+ xfer->segs_done++;
+
+ /* check for done. */
+ return __wa_xfer_is_done(xfer);
+}
+
+/*
+ * Search for a transfer list ID on the HCD's URB list
+ *
+ * For 32 bit architectures, we use the pointer itself; for 64 bits, a
+ * 32-bit hash of the pointer.
+ *
+ * @returns NULL if not found.
+ */
+static struct wa_xfer *wa_xfer_get_by_id(struct wahc *wa, u32 id)
+{
+ unsigned long flags;
+ struct wa_xfer *xfer_itr;
+ spin_lock_irqsave(&wa->xfer_list_lock, flags);
+ list_for_each_entry(xfer_itr, &wa->xfer_list, list_node) {
+ if (id == xfer_itr->id) {
+ wa_xfer_get(xfer_itr);
+ goto out;
+ }
+ }
+ xfer_itr = NULL;
+out:
+ spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
+ return xfer_itr;
+}
+
+struct wa_xfer_abort_buffer {
+ struct urb urb;
+ struct wahc *wa;
+ struct wa_xfer_abort cmd;
+};
+
+static void __wa_xfer_abort_cb(struct urb *urb)
+{
+ struct wa_xfer_abort_buffer *b = urb->context;
+ struct wahc *wa = b->wa;
+
+ /*
+ * If the abort request URB failed, then the HWA did not get the abort
+ * command. Forcibly clean up the xfer without waiting for a Transfer
+ * Result from the HWA.
+ */
+ if (urb->status < 0) {
+ struct wa_xfer *xfer;
+ struct device *dev = &wa->usb_iface->dev;
+
+ xfer = wa_xfer_get_by_id(wa, le32_to_cpu(b->cmd.dwTransferID));
+ dev_err(dev, "%s: Transfer Abort request failed. result: %d\n",
+ __func__, urb->status);
+ if (xfer) {
+ unsigned long flags;
+ int done, seg_index = 0;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+ dev_err(dev, "%s: cleaning up xfer %p ID 0x%08X.\n",
+ __func__, xfer, wa_xfer_id(xfer));
+ spin_lock_irqsave(&xfer->lock, flags);
+ /* skip done segs. */
+ while (seg_index < xfer->segs) {
+ struct wa_seg *seg = xfer->seg[seg_index];
+
+ if ((seg->status == WA_SEG_DONE) ||
+ (seg->status == WA_SEG_ERROR)) {
+ ++seg_index;
+ } else {
+ break;
+ }
+ }
+ /* mark remaining segs as aborted. */
+ wa_complete_remaining_xfer_segs(xfer, seg_index,
+ WA_SEG_ABORTED);
+ done = __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ wa_xfer_delayed_run(rpipe);
+ wa_xfer_put(xfer);
+ } else {
+ dev_err(dev, "%s: xfer ID 0x%08X already gone.\n",
+ __func__, le32_to_cpu(b->cmd.dwTransferID));
+ }
+ }
+
+ wa_put(wa); /* taken in __wa_xfer_abort */
+ usb_put_urb(&b->urb);
+}
+
+/*
+ * Aborts an ongoing transaction
+ *
+ * Assumes the transfer is referenced and locked and in a submitted
+ * state (mainly that there is an endpoint/rpipe assigned).
+ *
+ * The callback (see above) does nothing but freeing up the data by
+ * putting the URB. Because the URB is allocated at the head of the
+ * struct, the whole space we allocated is kfreed. *
+ */
+static int __wa_xfer_abort(struct wa_xfer *xfer)
+{
+ int result = -ENOMEM;
+ struct device *dev = &xfer->wa->usb_iface->dev;
+ struct wa_xfer_abort_buffer *b;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+ b = kmalloc(sizeof(*b), GFP_ATOMIC);
+ if (b == NULL)
+ goto error_kmalloc;
+ b->cmd.bLength = sizeof(b->cmd);
+ b->cmd.bRequestType = WA_XFER_ABORT;
+ b->cmd.wRPipe = rpipe->descr.wRPipeIndex;
+ b->cmd.dwTransferID = wa_xfer_id_le32(xfer);
+ b->wa = wa_get(xfer->wa);
+
+ usb_init_urb(&b->urb);
+ usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev,
+ usb_sndbulkpipe(xfer->wa->usb_dev,
+ xfer->wa->dto_epd->bEndpointAddress),
+ &b->cmd, sizeof(b->cmd), __wa_xfer_abort_cb, b);
+ result = usb_submit_urb(&b->urb, GFP_ATOMIC);
+ if (result < 0)
+ goto error_submit;
+ return result; /* callback frees! */
+
+
+error_submit:
+ wa_put(xfer->wa);
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p: Can't submit abort request: %d\n",
+ xfer, result);
+ kfree(b);
+error_kmalloc:
+ return result;
+
+}
+
+/*
+ * Calculate the number of isoc frames starting from isoc_frame_offset
+ * that will fit a in transfer segment.
+ */
+static int __wa_seg_calculate_isoc_frame_count(struct wa_xfer *xfer,
+ int isoc_frame_offset, int *total_size)
+{
+ int segment_size = 0, frame_count = 0;
+ int index = isoc_frame_offset;
+ struct usb_iso_packet_descriptor *iso_frame_desc =
+ xfer->urb->iso_frame_desc;
+
+ while ((index < xfer->urb->number_of_packets)
+ && ((segment_size + iso_frame_desc[index].length)
+ <= xfer->seg_size)) {
+ /*
+ * For Alereon HWA devices, only include an isoc frame in an
+ * out segment if it is physically contiguous with the previous
+ * frame. This is required because those devices expect
+ * the isoc frames to be sent as a single USB transaction as
+ * opposed to one transaction per frame with standard HWA.
+ */
+ if ((xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
+ && (xfer->is_inbound == 0)
+ && (index > isoc_frame_offset)
+ && ((iso_frame_desc[index - 1].offset +
+ iso_frame_desc[index - 1].length) !=
+ iso_frame_desc[index].offset))
+ break;
+
+ /* this frame fits. count it. */
+ ++frame_count;
+ segment_size += iso_frame_desc[index].length;
+
+ /* move to the next isoc frame. */
+ ++index;
+ }
+
+ *total_size = segment_size;
+ return frame_count;
+}
+
+/*
+ *
+ * @returns < 0 on error, transfer segment request size if ok
+ */
+static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,
+ enum wa_xfer_type *pxfer_type)
+{
+ ssize_t result;
+ struct device *dev = &xfer->wa->usb_iface->dev;
+ size_t maxpktsize;
+ struct urb *urb = xfer->urb;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+ switch (rpipe->descr.bmAttribute & 0x3) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ *pxfer_type = WA_XFER_TYPE_CTL;
+ result = sizeof(struct wa_xfer_ctl);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ case USB_ENDPOINT_XFER_BULK:
+ *pxfer_type = WA_XFER_TYPE_BI;
+ result = sizeof(struct wa_xfer_bi);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ *pxfer_type = WA_XFER_TYPE_ISO;
+ result = sizeof(struct wa_xfer_hwaiso);
+ break;
+ default:
+ /* never happens */
+ BUG();
+ result = -EINVAL; /* shut gcc up */
+ }
+ xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0;
+ xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0;
+
+ maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize);
+ xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks)
+ * 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1);
+ /* Compute the segment size and make sure it is a multiple of
+ * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of
+ * a check (FIXME) */
+ if (xfer->seg_size < maxpktsize) {
+ dev_err(dev,
+ "HW BUG? seg_size %zu smaller than maxpktsize %zu\n",
+ xfer->seg_size, maxpktsize);
+ result = -EINVAL;
+ goto error;
+ }
+ xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize;
+ if ((rpipe->descr.bmAttribute & 0x3) == USB_ENDPOINT_XFER_ISOC) {
+ int index = 0;
+
+ xfer->segs = 0;
+ /*
+ * loop over urb->number_of_packets to determine how many
+ * xfer segments will be needed to send the isoc frames.
+ */
+ while (index < urb->number_of_packets) {
+ int seg_size; /* don't care. */
+ index += __wa_seg_calculate_isoc_frame_count(xfer,
+ index, &seg_size);
+ ++xfer->segs;
+ }
+ } else {
+ xfer->segs = DIV_ROUND_UP(urb->transfer_buffer_length,
+ xfer->seg_size);
+ if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL)
+ xfer->segs = 1;
+ }
+
+ if (xfer->segs > WA_SEGS_MAX) {
+ dev_err(dev, "BUG? oops, number of segments %zu bigger than %d\n",
+ (urb->transfer_buffer_length/xfer->seg_size),
+ WA_SEGS_MAX);
+ result = -EINVAL;
+ goto error;
+ }
+error:
+ return result;
+}
+
+static void __wa_setup_isoc_packet_descr(
+ struct wa_xfer_packet_info_hwaiso *packet_desc,
+ struct wa_xfer *xfer,
+ struct wa_seg *seg) {
+ struct usb_iso_packet_descriptor *iso_frame_desc =
+ xfer->urb->iso_frame_desc;
+ int frame_index;
+
+ /* populate isoc packet descriptor. */
+ packet_desc->bPacketType = WA_XFER_ISO_PACKET_INFO;
+ packet_desc->wLength = cpu_to_le16(struct_size(packet_desc,
+ PacketLength,
+ seg->isoc_frame_count));
+ for (frame_index = 0; frame_index < seg->isoc_frame_count;
+ ++frame_index) {
+ int offset_index = frame_index + seg->isoc_frame_offset;
+ packet_desc->PacketLength[frame_index] =
+ cpu_to_le16(iso_frame_desc[offset_index].length);
+ }
+}
+
+
+/* Fill in the common request header and xfer-type specific data. */
+static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,
+ struct wa_xfer_hdr *xfer_hdr0,
+ enum wa_xfer_type xfer_type,
+ size_t xfer_hdr_size)
+{
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+ struct wa_seg *seg = xfer->seg[0];
+
+ xfer_hdr0 = &seg->xfer_hdr;
+ xfer_hdr0->bLength = xfer_hdr_size;
+ xfer_hdr0->bRequestType = xfer_type;
+ xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex;
+ xfer_hdr0->dwTransferID = wa_xfer_id_le32(xfer);
+ xfer_hdr0->bTransferSegment = 0;
+ switch (xfer_type) {
+ case WA_XFER_TYPE_CTL: {
+ struct wa_xfer_ctl *xfer_ctl =
+ container_of(xfer_hdr0, struct wa_xfer_ctl, hdr);
+ xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0;
+ memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet,
+ sizeof(xfer_ctl->baSetupData));
+ break;
+ }
+ case WA_XFER_TYPE_BI:
+ break;
+ case WA_XFER_TYPE_ISO: {
+ struct wa_xfer_hwaiso *xfer_iso =
+ container_of(xfer_hdr0, struct wa_xfer_hwaiso, hdr);
+ struct wa_xfer_packet_info_hwaiso *packet_desc =
+ ((void *)xfer_iso) + xfer_hdr_size;
+
+ /* populate the isoc section of the transfer request. */
+ xfer_iso->dwNumOfPackets = cpu_to_le32(seg->isoc_frame_count);
+ /* populate isoc packet descriptor. */
+ __wa_setup_isoc_packet_descr(packet_desc, xfer, seg);
+ break;
+ }
+ default:
+ BUG();
+ };
+}
+
+/*
+ * Callback for the OUT data phase of the segment request
+ *
+ * Check wa_seg_tr_cb(); most comments also apply here because this
+ * function does almost the same thing and they work closely
+ * together.
+ *
+ * If the seg request has failed but this DTO phase has succeeded,
+ * wa_seg_tr_cb() has already failed the segment and moved the
+ * status to WA_SEG_ERROR, so this will go through 'case 0' and
+ * effectively do nothing.
+ */
+static void wa_seg_dto_cb(struct urb *urb)
+{
+ struct wa_seg *seg = urb->context;
+ struct wa_xfer *xfer = seg->xfer;
+ struct wahc *wa;
+ struct device *dev;
+ struct wa_rpipe *rpipe;
+ unsigned long flags;
+ unsigned rpipe_ready = 0;
+ int data_send_done = 1, release_dto = 0, holding_dto = 0;
+ u8 done = 0;
+ int result;
+
+ /* free the sg if it was used. */
+ kfree(urb->sg);
+ urb->sg = NULL;
+
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ if (usb_pipeisoc(xfer->urb->pipe)) {
+ /* Alereon HWA sends all isoc frames in a single transfer. */
+ if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
+ seg->isoc_frame_index += seg->isoc_frame_count;
+ else
+ seg->isoc_frame_index += 1;
+ if (seg->isoc_frame_index < seg->isoc_frame_count) {
+ data_send_done = 0;
+ holding_dto = 1; /* checked in error cases. */
+ /*
+ * if this is the last isoc frame of the segment, we
+ * can release DTO after sending this frame.
+ */
+ if ((seg->isoc_frame_index + 1) >=
+ seg->isoc_frame_count)
+ release_dto = 1;
+ }
+ dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n",
+ wa_xfer_id(xfer), seg->index, seg->isoc_frame_index,
+ holding_dto, release_dto);
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+
+ switch (urb->status) {
+ case 0:
+ spin_lock_irqsave(&xfer->lock, flags);
+ seg->result += urb->actual_length;
+ if (data_send_done) {
+ dev_dbg(dev, "xfer 0x%08X#%u: data out done (%zu bytes)\n",
+ wa_xfer_id(xfer), seg->index, seg->result);
+ if (seg->status < WA_SEG_PENDING)
+ seg->status = WA_SEG_PENDING;
+ } else {
+ /* should only hit this for isoc xfers. */
+ /*
+ * Populate the dto URB with the next isoc frame buffer,
+ * send the URB and release DTO if we no longer need it.
+ */
+ __wa_populate_dto_urb_isoc(xfer, seg,
+ seg->isoc_frame_offset + seg->isoc_frame_index);
+
+ /* resubmit the URB with the next isoc frame. */
+ /* take a ref on resubmit. */
+ wa_xfer_get(xfer);
+ result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "xfer 0x%08X#%u: DTO submit failed: %d\n",
+ wa_xfer_id(xfer), seg->index, result);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ goto error_dto_submit;
+ }
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (release_dto) {
+ __wa_dto_put(wa);
+ wa_check_for_delayed_rpipes(wa);
+ }
+ break;
+ case -ECONNRESET: /* URB unlinked; no need to do anything */
+ case -ENOENT: /* as it was done by the who unlinked us */
+ if (holding_dto) {
+ __wa_dto_put(wa);
+ wa_check_for_delayed_rpipes(wa);
+ }
+ break;
+ default: /* Other errors ... */
+ dev_err(dev, "xfer 0x%08X#%u: data out error %d\n",
+ wa_xfer_id(xfer), seg->index, urb->status);
+ goto error_default;
+ }
+
+ /* taken when this URB was submitted. */
+ wa_xfer_put(xfer);
+ return;
+
+error_dto_submit:
+ /* taken on resubmit attempt. */
+ wa_xfer_put(xfer);
+error_default:
+ spin_lock_irqsave(&xfer->lock, flags);
+ rpipe = xfer->ep->hcpriv;
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)){
+ dev_err(dev, "DTO: URB max acceptable errors exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ if (seg->status != WA_SEG_ERROR) {
+ seg->result = urb->status;
+ __wa_xfer_abort(xfer);
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (holding_dto) {
+ __wa_dto_put(wa);
+ wa_check_for_delayed_rpipes(wa);
+ }
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ /* taken when this URB was submitted. */
+ wa_xfer_put(xfer);
+}
+
+/*
+ * Callback for the isoc packet descriptor phase of the segment request
+ *
+ * Check wa_seg_tr_cb(); most comments also apply here because this
+ * function does almost the same thing and they work closely
+ * together.
+ *
+ * If the seg request has failed but this phase has succeeded,
+ * wa_seg_tr_cb() has already failed the segment and moved the
+ * status to WA_SEG_ERROR, so this will go through 'case 0' and
+ * effectively do nothing.
+ */
+static void wa_seg_iso_pack_desc_cb(struct urb *urb)
+{
+ struct wa_seg *seg = urb->context;
+ struct wa_xfer *xfer = seg->xfer;
+ struct wahc *wa;
+ struct device *dev;
+ struct wa_rpipe *rpipe;
+ unsigned long flags;
+ unsigned rpipe_ready = 0;
+ u8 done = 0;
+
+ switch (urb->status) {
+ case 0:
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ dev_dbg(dev, "iso xfer %08X#%u: packet descriptor done\n",
+ wa_xfer_id(xfer), seg->index);
+ if (xfer->is_inbound && seg->status < WA_SEG_PENDING)
+ seg->status = WA_SEG_PENDING;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ break;
+ case -ECONNRESET: /* URB unlinked; no need to do anything */
+ case -ENOENT: /* as it was done by the who unlinked us */
+ break;
+ default: /* Other errors ... */
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ rpipe = xfer->ep->hcpriv;
+ pr_err_ratelimited("iso xfer %08X#%u: packet descriptor error %d\n",
+ wa_xfer_id(xfer), seg->index, urb->status);
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)){
+ dev_err(dev, "iso xfer: URB max acceptable errors exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ if (seg->status != WA_SEG_ERROR) {
+ usb_unlink_urb(seg->dto_urb);
+ seg->result = urb->status;
+ __wa_xfer_abort(xfer);
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg,
+ WA_SEG_ERROR);
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ }
+ /* taken when this URB was submitted. */
+ wa_xfer_put(xfer);
+}
+
+/*
+ * Callback for the segment request
+ *
+ * If successful transition state (unless already transitioned or
+ * outbound transfer); otherwise, take a note of the error, mark this
+ * segment done and try completion.
+ *
+ * Note we don't access until we are sure that the transfer hasn't
+ * been cancelled (ECONNRESET, ENOENT), which could mean that
+ * seg->xfer could be already gone.
+ *
+ * We have to check before setting the status to WA_SEG_PENDING
+ * because sometimes the xfer result callback arrives before this
+ * callback (geeeeeeze), so it might happen that we are already in
+ * another state. As well, we don't set it if the transfer is not inbound,
+ * as in that case, wa_seg_dto_cb will do it when the OUT data phase
+ * finishes.
+ */
+static void wa_seg_tr_cb(struct urb *urb)
+{
+ struct wa_seg *seg = urb->context;
+ struct wa_xfer *xfer = seg->xfer;
+ struct wahc *wa;
+ struct device *dev;
+ struct wa_rpipe *rpipe;
+ unsigned long flags;
+ unsigned rpipe_ready;
+ u8 done = 0;
+
+ switch (urb->status) {
+ case 0:
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ dev_dbg(dev, "xfer %p ID 0x%08X#%u: request done\n",
+ xfer, wa_xfer_id(xfer), seg->index);
+ if (xfer->is_inbound &&
+ seg->status < WA_SEG_PENDING &&
+ !(usb_pipeisoc(xfer->urb->pipe)))
+ seg->status = WA_SEG_PENDING;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ break;
+ case -ECONNRESET: /* URB unlinked; no need to do anything */
+ case -ENOENT: /* as it was done by the who unlinked us */
+ break;
+ default: /* Other errors ... */
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ rpipe = xfer->ep->hcpriv;
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p ID 0x%08X#%u: request error %d\n",
+ xfer, wa_xfer_id(xfer), seg->index,
+ urb->status);
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)){
+ dev_err(dev, "DTO: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ usb_unlink_urb(seg->isoc_pack_desc_urb);
+ usb_unlink_urb(seg->dto_urb);
+ seg->result = urb->status;
+ __wa_xfer_abort(xfer);
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ }
+ /* taken when this URB was submitted. */
+ wa_xfer_put(xfer);
+}
+
+/*
+ * Allocate an SG list to store bytes_to_transfer bytes and copy the
+ * subset of the in_sg that matches the buffer subset
+ * we are about to transfer.
+ */
+static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
+ const unsigned int bytes_transferred,
+ const unsigned int bytes_to_transfer, int *out_num_sgs)
+{
+ struct scatterlist *out_sg;
+ unsigned int bytes_processed = 0, offset_into_current_page_data = 0,
+ nents;
+ struct scatterlist *current_xfer_sg = in_sg;
+ struct scatterlist *current_seg_sg, *last_seg_sg;
+
+ /* skip previously transferred pages. */
+ while ((current_xfer_sg) &&
+ (bytes_processed < bytes_transferred)) {
+ bytes_processed += current_xfer_sg->length;
+
+ /* advance the sg if current segment starts on or past the
+ next page. */
+ if (bytes_processed <= bytes_transferred)
+ current_xfer_sg = sg_next(current_xfer_sg);
+ }
+
+ /* the data for the current segment starts in current_xfer_sg.
+ calculate the offset. */
+ if (bytes_processed > bytes_transferred) {
+ offset_into_current_page_data = current_xfer_sg->length -
+ (bytes_processed - bytes_transferred);
+ }
+
+ /* calculate the number of pages needed by this segment. */
+ nents = DIV_ROUND_UP((bytes_to_transfer +
+ offset_into_current_page_data +
+ current_xfer_sg->offset),
+ PAGE_SIZE);
+
+ out_sg = kmalloc((sizeof(struct scatterlist) * nents), GFP_ATOMIC);
+ if (out_sg) {
+ sg_init_table(out_sg, nents);
+
+ /* copy the portion of the incoming SG that correlates to the
+ * data to be transferred by this segment to the segment SG. */
+ last_seg_sg = current_seg_sg = out_sg;
+ bytes_processed = 0;
+
+ /* reset nents and calculate the actual number of sg entries
+ needed. */
+ nents = 0;
+ while ((bytes_processed < bytes_to_transfer) &&
+ current_seg_sg && current_xfer_sg) {
+ unsigned int page_len = min((current_xfer_sg->length -
+ offset_into_current_page_data),
+ (bytes_to_transfer - bytes_processed));
+
+ sg_set_page(current_seg_sg, sg_page(current_xfer_sg),
+ page_len,
+ current_xfer_sg->offset +
+ offset_into_current_page_data);
+
+ bytes_processed += page_len;
+
+ last_seg_sg = current_seg_sg;
+ current_seg_sg = sg_next(current_seg_sg);
+ current_xfer_sg = sg_next(current_xfer_sg);
+
+ /* only the first page may require additional offset. */
+ offset_into_current_page_data = 0;
+ nents++;
+ }
+
+ /* update num_sgs and terminate the list since we may have
+ * concatenated pages. */
+ sg_mark_end(last_seg_sg);
+ *out_num_sgs = nents;
+ }
+
+ return out_sg;
+}
+
+/*
+ * Populate DMA buffer info for the isoc dto urb.
+ */
+static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
+ struct wa_seg *seg, int curr_iso_frame)
+{
+ seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ seg->dto_urb->sg = NULL;
+ seg->dto_urb->num_sgs = 0;
+ /* dto urb buffer address pulled from iso_frame_desc. */
+ seg->dto_urb->transfer_dma = xfer->urb->transfer_dma +
+ xfer->urb->iso_frame_desc[curr_iso_frame].offset;
+ /* The Alereon HWA sends a single URB with all isoc segs. */
+ if (xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
+ seg->dto_urb->transfer_buffer_length = seg->isoc_size;
+ else
+ seg->dto_urb->transfer_buffer_length =
+ xfer->urb->iso_frame_desc[curr_iso_frame].length;
+}
+
+/*
+ * Populate buffer ptr and size, DMA buffer or SG list for the dto urb.
+ */
+static int __wa_populate_dto_urb(struct wa_xfer *xfer,
+ struct wa_seg *seg, size_t buf_itr_offset, size_t buf_itr_size)
+{
+ int result = 0;
+
+ if (xfer->is_dma) {
+ seg->dto_urb->transfer_dma =
+ xfer->urb->transfer_dma + buf_itr_offset;
+ seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ seg->dto_urb->sg = NULL;
+ seg->dto_urb->num_sgs = 0;
+ } else {
+ /* do buffer or SG processing. */
+ seg->dto_urb->transfer_flags &=
+ ~URB_NO_TRANSFER_DMA_MAP;
+ /* this should always be 0 before a resubmit. */
+ seg->dto_urb->num_mapped_sgs = 0;
+
+ if (xfer->urb->transfer_buffer) {
+ seg->dto_urb->transfer_buffer =
+ xfer->urb->transfer_buffer +
+ buf_itr_offset;
+ seg->dto_urb->sg = NULL;
+ seg->dto_urb->num_sgs = 0;
+ } else {
+ seg->dto_urb->transfer_buffer = NULL;
+
+ /*
+ * allocate an SG list to store seg_size bytes
+ * and copy the subset of the xfer->urb->sg that
+ * matches the buffer subset we are about to
+ * read.
+ */
+ seg->dto_urb->sg = wa_xfer_create_subset_sg(
+ xfer->urb->sg,
+ buf_itr_offset, buf_itr_size,
+ &(seg->dto_urb->num_sgs));
+ if (!(seg->dto_urb->sg))
+ result = -ENOMEM;
+ }
+ }
+ seg->dto_urb->transfer_buffer_length = buf_itr_size;
+
+ return result;
+}
+
+/*
+ * Allocate the segs array and initialize each of them
+ *
+ * The segments are freed by wa_xfer_destroy() when the xfer use count
+ * drops to zero; however, because each segment is given the same life
+ * cycle as the USB URB it contains, it is actually freed by
+ * usb_put_urb() on the contained USB URB (twisted, eh?).
+ */
+static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
+{
+ int result, cnt, isoc_frame_offset = 0;
+ size_t alloc_size = sizeof(*xfer->seg[0])
+ - sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size;
+ struct usb_device *usb_dev = xfer->wa->usb_dev;
+ const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd;
+ struct wa_seg *seg;
+ size_t buf_itr, buf_size, buf_itr_size;
+
+ result = -ENOMEM;
+ xfer->seg = kcalloc(xfer->segs, sizeof(xfer->seg[0]), GFP_ATOMIC);
+ if (xfer->seg == NULL)
+ goto error_segs_kzalloc;
+ buf_itr = 0;
+ buf_size = xfer->urb->transfer_buffer_length;
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ size_t iso_pkt_descr_size = 0;
+ int seg_isoc_frame_count = 0, seg_isoc_size = 0;
+
+ /*
+ * Adjust the size of the segment object to contain space for
+ * the isoc packet descriptor buffer.
+ */
+ if (usb_pipeisoc(xfer->urb->pipe)) {
+ seg_isoc_frame_count =
+ __wa_seg_calculate_isoc_frame_count(xfer,
+ isoc_frame_offset, &seg_isoc_size);
+
+ iso_pkt_descr_size =
+ sizeof(struct wa_xfer_packet_info_hwaiso) +
+ (seg_isoc_frame_count * sizeof(__le16));
+ }
+ result = -ENOMEM;
+ seg = xfer->seg[cnt] = kmalloc(alloc_size + iso_pkt_descr_size,
+ GFP_ATOMIC);
+ if (seg == NULL)
+ goto error_seg_kmalloc;
+ wa_seg_init(seg);
+ seg->xfer = xfer;
+ seg->index = cnt;
+ usb_fill_bulk_urb(&seg->tr_urb, usb_dev,
+ usb_sndbulkpipe(usb_dev,
+ dto_epd->bEndpointAddress),
+ &seg->xfer_hdr, xfer_hdr_size,
+ wa_seg_tr_cb, seg);
+ buf_itr_size = min(buf_size, xfer->seg_size);
+
+ if (usb_pipeisoc(xfer->urb->pipe)) {
+ seg->isoc_frame_count = seg_isoc_frame_count;
+ seg->isoc_frame_offset = isoc_frame_offset;
+ seg->isoc_size = seg_isoc_size;
+ /* iso packet descriptor. */
+ seg->isoc_pack_desc_urb =
+ usb_alloc_urb(0, GFP_ATOMIC);
+ if (seg->isoc_pack_desc_urb == NULL)
+ goto error_iso_pack_desc_alloc;
+ /*
+ * The buffer for the isoc packet descriptor starts
+ * after the transfer request header in the
+ * segment object memory buffer.
+ */
+ usb_fill_bulk_urb(
+ seg->isoc_pack_desc_urb, usb_dev,
+ usb_sndbulkpipe(usb_dev,
+ dto_epd->bEndpointAddress),
+ (void *)(&seg->xfer_hdr) +
+ xfer_hdr_size,
+ iso_pkt_descr_size,
+ wa_seg_iso_pack_desc_cb, seg);
+
+ /* adjust starting frame offset for next seg. */
+ isoc_frame_offset += seg_isoc_frame_count;
+ }
+
+ if (xfer->is_inbound == 0 && buf_size > 0) {
+ /* outbound data. */
+ seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (seg->dto_urb == NULL)
+ goto error_dto_alloc;
+ usb_fill_bulk_urb(
+ seg->dto_urb, usb_dev,
+ usb_sndbulkpipe(usb_dev,
+ dto_epd->bEndpointAddress),
+ NULL, 0, wa_seg_dto_cb, seg);
+
+ if (usb_pipeisoc(xfer->urb->pipe)) {
+ /*
+ * Fill in the xfer buffer information for the
+ * first isoc frame. Subsequent frames in this
+ * segment will be filled in and sent from the
+ * DTO completion routine, if needed.
+ */
+ __wa_populate_dto_urb_isoc(xfer, seg,
+ seg->isoc_frame_offset);
+ } else {
+ /* fill in the xfer buffer information. */
+ result = __wa_populate_dto_urb(xfer, seg,
+ buf_itr, buf_itr_size);
+ if (result < 0)
+ goto error_seg_outbound_populate;
+
+ buf_itr += buf_itr_size;
+ buf_size -= buf_itr_size;
+ }
+ }
+ seg->status = WA_SEG_READY;
+ }
+ return 0;
+
+ /*
+ * Free the memory for the current segment which failed to init.
+ * Use the fact that cnt is left at were it failed. The remaining
+ * segments will be cleaned up by wa_xfer_destroy.
+ */
+error_seg_outbound_populate:
+ usb_free_urb(xfer->seg[cnt]->dto_urb);
+error_dto_alloc:
+ usb_free_urb(xfer->seg[cnt]->isoc_pack_desc_urb);
+error_iso_pack_desc_alloc:
+ kfree(xfer->seg[cnt]);
+ xfer->seg[cnt] = NULL;
+error_seg_kmalloc:
+error_segs_kzalloc:
+ return result;
+}
+
+/*
+ * Allocates all the stuff needed to submit a transfer
+ *
+ * Breaks the whole data buffer in a list of segments, each one has a
+ * structure allocated to it and linked in xfer->seg[index]
+ *
+ * FIXME: merge setup_segs() and the last part of this function, no
+ * need to do two for loops when we could run everything in a
+ * single one
+ */
+static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb)
+{
+ int result;
+ struct device *dev = &xfer->wa->usb_iface->dev;
+ enum wa_xfer_type xfer_type = 0; /* shut up GCC */
+ size_t xfer_hdr_size, cnt, transfer_size;
+ struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr;
+
+ result = __wa_xfer_setup_sizes(xfer, &xfer_type);
+ if (result < 0)
+ goto error_setup_sizes;
+ xfer_hdr_size = result;
+ result = __wa_xfer_setup_segs(xfer, xfer_hdr_size);
+ if (result < 0) {
+ dev_err(dev, "xfer %p: Failed to allocate %d segments: %d\n",
+ xfer, xfer->segs, result);
+ goto error_setup_segs;
+ }
+ /* Fill the first header */
+ xfer_hdr0 = &xfer->seg[0]->xfer_hdr;
+ wa_xfer_id_init(xfer);
+ __wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size);
+
+ /* Fill remaining headers */
+ xfer_hdr = xfer_hdr0;
+ if (xfer_type == WA_XFER_TYPE_ISO) {
+ xfer_hdr0->dwTransferLength =
+ cpu_to_le32(xfer->seg[0]->isoc_size);
+ for (cnt = 1; cnt < xfer->segs; cnt++) {
+ struct wa_xfer_packet_info_hwaiso *packet_desc;
+ struct wa_seg *seg = xfer->seg[cnt];
+ struct wa_xfer_hwaiso *xfer_iso;
+
+ xfer_hdr = &seg->xfer_hdr;
+ xfer_iso = container_of(xfer_hdr,
+ struct wa_xfer_hwaiso, hdr);
+ packet_desc = ((void *)xfer_hdr) + xfer_hdr_size;
+ /*
+ * Copy values from the 0th header. Segment specific
+ * values are set below.
+ */
+ memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
+ xfer_hdr->bTransferSegment = cnt;
+ xfer_hdr->dwTransferLength =
+ cpu_to_le32(seg->isoc_size);
+ xfer_iso->dwNumOfPackets =
+ cpu_to_le32(seg->isoc_frame_count);
+ __wa_setup_isoc_packet_descr(packet_desc, xfer, seg);
+ seg->status = WA_SEG_READY;
+ }
+ } else {
+ transfer_size = urb->transfer_buffer_length;
+ xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ?
+ cpu_to_le32(xfer->seg_size) :
+ cpu_to_le32(transfer_size);
+ transfer_size -= xfer->seg_size;
+ for (cnt = 1; cnt < xfer->segs; cnt++) {
+ xfer_hdr = &xfer->seg[cnt]->xfer_hdr;
+ memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
+ xfer_hdr->bTransferSegment = cnt;
+ xfer_hdr->dwTransferLength =
+ transfer_size > xfer->seg_size ?
+ cpu_to_le32(xfer->seg_size)
+ : cpu_to_le32(transfer_size);
+ xfer->seg[cnt]->status = WA_SEG_READY;
+ transfer_size -= xfer->seg_size;
+ }
+ }
+ xfer_hdr->bTransferSegment |= 0x80; /* this is the last segment */
+ result = 0;
+error_setup_segs:
+error_setup_sizes:
+ return result;
+}
+
+/*
+ *
+ *
+ * rpipe->seg_lock is held!
+ */
+static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
+ struct wa_seg *seg, int *dto_done)
+{
+ int result;
+
+ /* default to done unless we encounter a multi-frame isoc segment. */
+ *dto_done = 1;
+
+ /*
+ * Take a ref for each segment urb so the xfer cannot disappear until
+ * all of the callbacks run.
+ */
+ wa_xfer_get(xfer);
+ /* submit the transfer request. */
+ seg->status = WA_SEG_SUBMITTED;
+ result = usb_submit_urb(&seg->tr_urb, GFP_ATOMIC);
+ if (result < 0) {
+ pr_err("%s: xfer %p#%u: REQ submit failed: %d\n",
+ __func__, xfer, seg->index, result);
+ wa_xfer_put(xfer);
+ goto error_tr_submit;
+ }
+ /* submit the isoc packet descriptor if present. */
+ if (seg->isoc_pack_desc_urb) {
+ wa_xfer_get(xfer);
+ result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC);
+ seg->isoc_frame_index = 0;
+ if (result < 0) {
+ pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n",
+ __func__, xfer, seg->index, result);
+ wa_xfer_put(xfer);
+ goto error_iso_pack_desc_submit;
+ }
+ }
+ /* submit the out data if this is an out request. */
+ if (seg->dto_urb) {
+ struct wahc *wa = xfer->wa;
+ wa_xfer_get(xfer);
+ result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
+ if (result < 0) {
+ pr_err("%s: xfer %p#%u: DTO submit failed: %d\n",
+ __func__, xfer, seg->index, result);
+ wa_xfer_put(xfer);
+ goto error_dto_submit;
+ }
+ /*
+ * If this segment contains more than one isoc frame, hold
+ * onto the dto resource until we send all frames.
+ * Only applies to non-Alereon devices.
+ */
+ if (((wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) == 0)
+ && (seg->isoc_frame_count > 1))
+ *dto_done = 0;
+ }
+ rpipe_avail_dec(rpipe);
+ return 0;
+
+error_dto_submit:
+ usb_unlink_urb(seg->isoc_pack_desc_urb);
+error_iso_pack_desc_submit:
+ usb_unlink_urb(&seg->tr_urb);
+error_tr_submit:
+ seg->status = WA_SEG_ERROR;
+ seg->result = result;
+ *dto_done = 1;
+ return result;
+}
+
+/*
+ * Execute more queued request segments until the maximum concurrent allowed.
+ * Return true if the DTO resource was acquired and released.
+ *
+ * The ugly unlock/lock sequence on the error path is needed as the
+ * xfer->lock normally nests the seg_lock and not viceversa.
+ */
+static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting)
+{
+ int result, dto_acquired = 0, dto_done = 0;
+ struct device *dev = &rpipe->wa->usb_iface->dev;
+ struct wa_seg *seg;
+ struct wa_xfer *xfer;
+ unsigned long flags;
+
+ *dto_waiting = 0;
+
+ spin_lock_irqsave(&rpipe->seg_lock, flags);
+ while (atomic_read(&rpipe->segs_available) > 0
+ && !list_empty(&rpipe->seg_list)
+ && (dto_acquired = __wa_dto_try_get(rpipe->wa))) {
+ seg = list_first_entry(&(rpipe->seg_list), struct wa_seg,
+ list_node);
+ list_del(&seg->list_node);
+ xfer = seg->xfer;
+ /*
+ * Get a reference to the xfer in case the callbacks for the
+ * URBs submitted by __wa_seg_submit attempt to complete
+ * the xfer before this function completes.
+ */
+ wa_xfer_get(xfer);
+ result = __wa_seg_submit(rpipe, xfer, seg, &dto_done);
+ /* release the dto resource if this RPIPE is done with it. */
+ if (dto_done)
+ __wa_dto_put(rpipe->wa);
+ dev_dbg(dev, "xfer %p ID %08X#%u submitted from delayed [%d segments available] %d\n",
+ xfer, wa_xfer_id(xfer), seg->index,
+ atomic_read(&rpipe->segs_available), result);
+ if (unlikely(result < 0)) {
+ int done;
+
+ spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+ spin_lock_irqsave(&xfer->lock, flags);
+ __wa_xfer_abort(xfer);
+ /*
+ * This seg was marked as submitted when it was put on
+ * the RPIPE seg_list. Mark it done.
+ */
+ xfer->segs_done++;
+ done = __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ spin_lock_irqsave(&rpipe->seg_lock, flags);
+ }
+ wa_xfer_put(xfer);
+ }
+ /*
+ * Mark this RPIPE as waiting if dto was not acquired, there are
+ * delayed segs and no active transfers to wake us up later.
+ */
+ if (!dto_acquired && !list_empty(&rpipe->seg_list)
+ && (atomic_read(&rpipe->segs_available) ==
+ le16_to_cpu(rpipe->descr.wRequests)))
+ *dto_waiting = 1;
+
+ spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+
+ return dto_done;
+}
+
+static void wa_xfer_delayed_run(struct wa_rpipe *rpipe)
+{
+ int dto_waiting;
+ int dto_done = __wa_xfer_delayed_run(rpipe, &dto_waiting);
+
+ /*
+ * If this RPIPE is waiting on the DTO resource, add it to the tail of
+ * the waiting list.
+ * Otherwise, if the WA DTO resource was acquired and released by
+ * __wa_xfer_delayed_run, another RPIPE may have attempted to acquire
+ * DTO and failed during that time. Check the delayed list and process
+ * any waiters. Start searching from the next RPIPE index.
+ */
+ if (dto_waiting)
+ wa_add_delayed_rpipe(rpipe->wa, rpipe);
+ else if (dto_done)
+ wa_check_for_delayed_rpipes(rpipe->wa);
+}
+
+/*
+ *
+ * xfer->lock is taken
+ *
+ * On failure submitting we just stop submitting and return error;
+ * wa_urb_enqueue_b() will execute the completion path
+ */
+static int __wa_xfer_submit(struct wa_xfer *xfer)
+{
+ int result, dto_acquired = 0, dto_done = 0, dto_waiting = 0;
+ struct wahc *wa = xfer->wa;
+ struct device *dev = &wa->usb_iface->dev;
+ unsigned cnt;
+ struct wa_seg *seg;
+ unsigned long flags;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+ size_t maxrequests = le16_to_cpu(rpipe->descr.wRequests);
+ u8 available;
+ u8 empty;
+
+ spin_lock_irqsave(&wa->xfer_list_lock, flags);
+ list_add_tail(&xfer->list_node, &wa->xfer_list);
+ spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
+
+ BUG_ON(atomic_read(&rpipe->segs_available) > maxrequests);
+ result = 0;
+ spin_lock_irqsave(&rpipe->seg_lock, flags);
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ int delay_seg = 1;
+
+ available = atomic_read(&rpipe->segs_available);
+ empty = list_empty(&rpipe->seg_list);
+ seg = xfer->seg[cnt];
+ if (available && empty) {
+ /*
+ * Only attempt to acquire DTO if we have a segment
+ * to send.
+ */
+ dto_acquired = __wa_dto_try_get(rpipe->wa);
+ if (dto_acquired) {
+ delay_seg = 0;
+ result = __wa_seg_submit(rpipe, xfer, seg,
+ &dto_done);
+ dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u submitted\n",
+ xfer, wa_xfer_id(xfer), cnt, available,
+ empty);
+ if (dto_done)
+ __wa_dto_put(rpipe->wa);
+
+ if (result < 0) {
+ __wa_xfer_abort(xfer);
+ goto error_seg_submit;
+ }
+ }
+ }
+
+ if (delay_seg) {
+ dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u delayed\n",
+ xfer, wa_xfer_id(xfer), cnt, available, empty);
+ seg->status = WA_SEG_DELAYED;
+ list_add_tail(&seg->list_node, &rpipe->seg_list);
+ }
+ xfer->segs_submitted++;
+ }
+error_seg_submit:
+ /*
+ * Mark this RPIPE as waiting if dto was not acquired, there are
+ * delayed segs and no active transfers to wake us up later.
+ */
+ if (!dto_acquired && !list_empty(&rpipe->seg_list)
+ && (atomic_read(&rpipe->segs_available) ==
+ le16_to_cpu(rpipe->descr.wRequests)))
+ dto_waiting = 1;
+ spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+
+ if (dto_waiting)
+ wa_add_delayed_rpipe(rpipe->wa, rpipe);
+ else if (dto_done)
+ wa_check_for_delayed_rpipes(rpipe->wa);
+
+ return result;
+}
+
+/*
+ * Second part of a URB/transfer enqueuement
+ *
+ * Assumes this comes from wa_urb_enqueue() [maybe through
+ * wa_urb_enqueue_run()]. At this point:
+ *
+ * xfer->wa filled and refcounted
+ * xfer->ep filled with rpipe refcounted if
+ * delayed == 0
+ * xfer->urb filled and refcounted (this is the case when called
+ * from wa_urb_enqueue() as we come from usb_submit_urb()
+ * and when called by wa_urb_enqueue_run(), as we took an
+ * extra ref dropped by _run() after we return).
+ * xfer->gfp filled
+ *
+ * If we fail at __wa_xfer_submit(), then we just check if we are done
+ * and if so, we run the completion procedure. However, if we are not
+ * yet done, we do nothing and wait for the completion handlers from
+ * the submitted URBs or from the xfer-result path to kick in. If xfer
+ * result never kicks in, the xfer will timeout from the USB code and
+ * dequeue() will be called.
+ */
+static int wa_urb_enqueue_b(struct wa_xfer *xfer)
+{
+ int result;
+ unsigned long flags;
+ struct urb *urb = xfer->urb;
+ struct wahc *wa = xfer->wa;
+ struct wusbhc *wusbhc = wa->wusb;
+ struct wusb_dev *wusb_dev;
+ unsigned done;
+
+ result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp);
+ if (result < 0) {
+ pr_err("%s: error_rpipe_get\n", __func__);
+ goto error_rpipe_get;
+ }
+ result = -ENODEV;
+ /* FIXME: segmentation broken -- kills DWA */
+ mutex_lock(&wusbhc->mutex); /* get a WUSB dev */
+ if (urb->dev == NULL) {
+ mutex_unlock(&wusbhc->mutex);
+ pr_err("%s: error usb dev gone\n", __func__);
+ goto error_dev_gone;
+ }
+ wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev);
+ if (wusb_dev == NULL) {
+ mutex_unlock(&wusbhc->mutex);
+ dev_err(&(urb->dev->dev), "%s: error wusb dev gone\n",
+ __func__);
+ goto error_dev_gone;
+ }
+ mutex_unlock(&wusbhc->mutex);
+
+ spin_lock_irqsave(&xfer->lock, flags);
+ xfer->wusb_dev = wusb_dev;
+ result = urb->status;
+ if (urb->status != -EINPROGRESS) {
+ dev_err(&(urb->dev->dev), "%s: error_dequeued\n", __func__);
+ goto error_dequeued;
+ }
+
+ result = __wa_xfer_setup(xfer, urb);
+ if (result < 0) {
+ dev_err(&(urb->dev->dev), "%s: error_xfer_setup\n", __func__);
+ goto error_xfer_setup;
+ }
+ /*
+ * Get a xfer reference since __wa_xfer_submit starts asynchronous
+ * operations that may try to complete the xfer before this function
+ * exits.
+ */
+ wa_xfer_get(xfer);
+ result = __wa_xfer_submit(xfer);
+ if (result < 0) {
+ dev_err(&(urb->dev->dev), "%s: error_xfer_submit\n", __func__);
+ goto error_xfer_submit;
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_xfer_put(xfer);
+ return 0;
+
+ /*
+ * this is basically wa_xfer_completion() broken up wa_xfer_giveback()
+ * does a wa_xfer_put() that will call wa_xfer_destroy() and undo
+ * setup().
+ */
+error_xfer_setup:
+error_dequeued:
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ /* FIXME: segmentation broken, kills DWA */
+ if (wusb_dev)
+ wusb_dev_put(wusb_dev);
+error_dev_gone:
+ rpipe_put(xfer->ep->hcpriv);
+error_rpipe_get:
+ xfer->result = result;
+ return result;
+
+error_xfer_submit:
+ done = __wa_xfer_is_done(xfer);
+ xfer->result = result;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ wa_xfer_put(xfer);
+ /* return success since the completion routine will run. */
+ return 0;
+}
+
+/*
+ * Execute the delayed transfers in the Wire Adapter @wa
+ *
+ * We need to be careful here, as dequeue() could be called in the
+ * middle. That's why we do the whole thing under the
+ * wa->xfer_list_lock. If dequeue() jumps in, it first locks xfer->lock
+ * and then checks the list -- so as we would be acquiring in inverse
+ * order, we move the delayed list to a separate list while locked and then
+ * submit them without the list lock held.
+ */
+void wa_urb_enqueue_run(struct work_struct *ws)
+{
+ struct wahc *wa = container_of(ws, struct wahc, xfer_enqueue_work);
+ struct wa_xfer *xfer, *next;
+ struct urb *urb;
+ LIST_HEAD(tmp_list);
+
+ /* Create a copy of the wa->xfer_delayed_list while holding the lock */
+ spin_lock_irq(&wa->xfer_list_lock);
+ list_cut_position(&tmp_list, &wa->xfer_delayed_list,
+ wa->xfer_delayed_list.prev);
+ spin_unlock_irq(&wa->xfer_list_lock);
+
+ /*
+ * enqueue from temp list without list lock held since wa_urb_enqueue_b
+ * can take xfer->lock as well as lock mutexes.
+ */
+ list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
+ list_del_init(&xfer->list_node);
+
+ urb = xfer->urb;
+ if (wa_urb_enqueue_b(xfer) < 0)
+ wa_xfer_giveback(xfer);
+ usb_put_urb(urb); /* taken when queuing */
+ }
+}
+EXPORT_SYMBOL_GPL(wa_urb_enqueue_run);
+
+/*
+ * Process the errored transfers on the Wire Adapter outside of interrupt.
+ */
+void wa_process_errored_transfers_run(struct work_struct *ws)
+{
+ struct wahc *wa = container_of(ws, struct wahc, xfer_error_work);
+ struct wa_xfer *xfer, *next;
+ LIST_HEAD(tmp_list);
+
+ pr_info("%s: Run delayed STALL processing.\n", __func__);
+
+ /* Create a copy of the wa->xfer_errored_list while holding the lock */
+ spin_lock_irq(&wa->xfer_list_lock);
+ list_cut_position(&tmp_list, &wa->xfer_errored_list,
+ wa->xfer_errored_list.prev);
+ spin_unlock_irq(&wa->xfer_list_lock);
+
+ /*
+ * run rpipe_clear_feature_stalled from temp list without list lock
+ * held.
+ */
+ list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
+ struct usb_host_endpoint *ep;
+ unsigned long flags;
+ struct wa_rpipe *rpipe;
+
+ spin_lock_irqsave(&xfer->lock, flags);
+ ep = xfer->ep;
+ rpipe = ep->hcpriv;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+
+ /* clear RPIPE feature stalled without holding a lock. */
+ rpipe_clear_feature_stalled(wa, ep);
+
+ /* complete the xfer. This removes it from the tmp list. */
+ wa_xfer_completion(xfer);
+
+ /* check for work. */
+ wa_xfer_delayed_run(rpipe);
+ }
+}
+EXPORT_SYMBOL_GPL(wa_process_errored_transfers_run);
+
+/*
+ * Submit a transfer to the Wire Adapter in a delayed way
+ *
+ * The process of enqueuing involves possible sleeps() [see
+ * enqueue_b(), for the rpipe_get() and the mutex_lock()]. If we are
+ * in an atomic section, we defer the enqueue_b() call--else we call direct.
+ *
+ * @urb: We own a reference to it done by the HCI Linux USB stack that
+ * will be given up by calling usb_hcd_giveback_urb() or by
+ * returning error from this function -> ergo we don't have to
+ * refcount it.
+ */
+int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,
+ struct urb *urb, gfp_t gfp)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_xfer *xfer;
+ unsigned long my_flags;
+ unsigned cant_sleep = irqs_disabled() | in_atomic();
+
+ if ((urb->transfer_buffer == NULL)
+ && (urb->sg == NULL)
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+ && urb->transfer_buffer_length != 0) {
+ dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb);
+ dump_stack();
+ }
+
+ spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+ result = usb_hcd_link_urb_to_ep(&(wa->wusb->usb_hcd), urb);
+ spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+ if (result < 0)
+ goto error_link_urb;
+
+ result = -ENOMEM;
+ xfer = kzalloc(sizeof(*xfer), gfp);
+ if (xfer == NULL)
+ goto error_kmalloc;
+
+ result = -ENOENT;
+ if (urb->status != -EINPROGRESS) /* cancelled */
+ goto error_dequeued; /* before starting? */
+ wa_xfer_init(xfer);
+ xfer->wa = wa_get(wa);
+ xfer->urb = urb;
+ xfer->gfp = gfp;
+ xfer->ep = ep;
+ urb->hcpriv = xfer;
+
+ dev_dbg(dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n",
+ xfer, urb, urb->pipe, urb->transfer_buffer_length,
+ urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma",
+ urb->pipe & USB_DIR_IN ? "inbound" : "outbound",
+ cant_sleep ? "deferred" : "inline");
+
+ if (cant_sleep) {
+ usb_get_urb(urb);
+ spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+ list_add_tail(&xfer->list_node, &wa->xfer_delayed_list);
+ spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+ queue_work(wusbd, &wa->xfer_enqueue_work);
+ } else {
+ result = wa_urb_enqueue_b(xfer);
+ if (result < 0) {
+ /*
+ * URB submit/enqueue failed. Clean up, return an
+ * error and do not run the callback. This avoids
+ * an infinite submit/complete loop.
+ */
+ dev_err(dev, "%s: URB enqueue failed: %d\n",
+ __func__, result);
+ wa_put(xfer->wa);
+ wa_xfer_put(xfer);
+ spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+ usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb);
+ spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+ return result;
+ }
+ }
+ return 0;
+
+error_dequeued:
+ kfree(xfer);
+error_kmalloc:
+ spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+ usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb);
+ spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+error_link_urb:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wa_urb_enqueue);
+
+/*
+ * Dequeue a URB and make sure uwb_hcd_giveback_urb() [completion
+ * handler] is called.
+ *
+ * Until a transfer goes successfully through wa_urb_enqueue() it
+ * needs to be dequeued with completion calling; when stuck in delayed
+ * or before wa_xfer_setup() is called, we need to do completion.
+ *
+ * not setup If there is no hcpriv yet, that means that that enqueue
+ * still had no time to set the xfer up. Because
+ * urb->status should be other than -EINPROGRESS,
+ * enqueue() will catch that and bail out.
+ *
+ * If the transfer has gone through setup, we just need to clean it
+ * up. If it has gone through submit(), we have to abort it [with an
+ * asynch request] and then make sure we cancel each segment.
+ *
+ */
+int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
+{
+ unsigned long flags;
+ struct wa_xfer *xfer;
+ struct wa_seg *seg;
+ struct wa_rpipe *rpipe;
+ unsigned cnt, done = 0, xfer_abort_pending;
+ unsigned rpipe_ready = 0;
+ int result;
+
+ /* check if it is safe to unlink. */
+ spin_lock_irqsave(&wa->xfer_list_lock, flags);
+ result = usb_hcd_check_unlink_urb(&(wa->wusb->usb_hcd), urb, status);
+ if ((result == 0) && urb->hcpriv) {
+ /*
+ * Get a xfer ref to prevent a race with wa_xfer_giveback
+ * cleaning up the xfer while we are working with it.
+ */
+ wa_xfer_get(urb->hcpriv);
+ }
+ spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
+ if (result)
+ return result;
+
+ xfer = urb->hcpriv;
+ if (xfer == NULL)
+ return -ENOENT;
+ spin_lock_irqsave(&xfer->lock, flags);
+ pr_debug("%s: DEQUEUE xfer id 0x%08X\n", __func__, wa_xfer_id(xfer));
+ rpipe = xfer->ep->hcpriv;
+ if (rpipe == NULL) {
+ pr_debug("%s: xfer %p id 0x%08X has no RPIPE. %s",
+ __func__, xfer, wa_xfer_id(xfer),
+ "Probably already aborted.\n" );
+ result = -ENOENT;
+ goto out_unlock;
+ }
+ /*
+ * Check for done to avoid racing with wa_xfer_giveback and completing
+ * twice.
+ */
+ if (__wa_xfer_is_done(xfer)) {
+ pr_debug("%s: xfer %p id 0x%08X already done.\n", __func__,
+ xfer, wa_xfer_id(xfer));
+ result = -ENOENT;
+ goto out_unlock;
+ }
+ /* Check the delayed list -> if there, release and complete */
+ spin_lock(&wa->xfer_list_lock);
+ if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
+ goto dequeue_delayed;
+ spin_unlock(&wa->xfer_list_lock);
+ if (xfer->seg == NULL) /* still hasn't reached */
+ goto out_unlock; /* setup(), enqueue_b() completes */
+ /* Ok, the xfer is in flight already, it's been setup and submitted.*/
+ xfer_abort_pending = __wa_xfer_abort(xfer) >= 0;
+ /*
+ * grab the rpipe->seg_lock here to prevent racing with
+ * __wa_xfer_delayed_run.
+ */
+ spin_lock(&rpipe->seg_lock);
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ seg = xfer->seg[cnt];
+ pr_debug("%s: xfer id 0x%08X#%d status = %d\n",
+ __func__, wa_xfer_id(xfer), cnt, seg->status);
+ switch (seg->status) {
+ case WA_SEG_NOTREADY:
+ case WA_SEG_READY:
+ printk(KERN_ERR "xfer %p#%u: dequeue bad state %u\n",
+ xfer, cnt, seg->status);
+ WARN_ON(1);
+ break;
+ case WA_SEG_DELAYED:
+ /*
+ * delete from rpipe delayed list. If no segments on
+ * this xfer have been submitted, __wa_xfer_is_done will
+ * trigger a giveback below. Otherwise, the submitted
+ * segments will be completed in the DTI interrupt.
+ */
+ seg->status = WA_SEG_ABORTED;
+ seg->result = -ENOENT;
+ list_del(&seg->list_node);
+ xfer->segs_done++;
+ break;
+ case WA_SEG_DONE:
+ case WA_SEG_ERROR:
+ case WA_SEG_ABORTED:
+ break;
+ /*
+ * The buf_in data for a segment in the
+ * WA_SEG_DTI_PENDING state is actively being read.
+ * Let wa_buf_in_cb handle it since it will be called
+ * and will increment xfer->segs_done. Cleaning up
+ * here could cause wa_buf_in_cb to access the xfer
+ * after it has been completed/freed.
+ */
+ case WA_SEG_DTI_PENDING:
+ break;
+ /*
+ * In the states below, the HWA device already knows
+ * about the transfer. If an abort request was sent,
+ * allow the HWA to process it and wait for the
+ * results. Otherwise, the DTI state and seg completed
+ * counts can get out of sync.
+ */
+ case WA_SEG_SUBMITTED:
+ case WA_SEG_PENDING:
+ /*
+ * Check if the abort was successfully sent. This could
+ * be false if the HWA has been removed but we haven't
+ * gotten the disconnect notification yet.
+ */
+ if (!xfer_abort_pending) {
+ seg->status = WA_SEG_ABORTED;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ xfer->segs_done++;
+ }
+ break;
+ }
+ }
+ spin_unlock(&rpipe->seg_lock);
+ xfer->result = urb->status; /* -ENOENT or -ECONNRESET */
+ done = __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ wa_xfer_put(xfer);
+ return result;
+
+out_unlock:
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_xfer_put(xfer);
+ return result;
+
+dequeue_delayed:
+ list_del_init(&xfer->list_node);
+ spin_unlock(&wa->xfer_list_lock);
+ xfer->result = urb->status;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_xfer_giveback(xfer);
+ wa_xfer_put(xfer);
+ usb_put_urb(urb); /* we got a ref in enqueue() */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wa_urb_dequeue);
+
+/*
+ * Translation from WA status codes (WUSB1.0 Table 8.15) to errno
+ * codes
+ *
+ * Positive errno values are internal inconsistencies and should be
+ * flagged louder. Negative are to be passed up to the user in the
+ * normal way.
+ *
+ * @status: USB WA status code -- high two bits are stripped.
+ */
+static int wa_xfer_status_to_errno(u8 status)
+{
+ int errno;
+ u8 real_status = status;
+ static int xlat[] = {
+ [WA_XFER_STATUS_SUCCESS] = 0,
+ [WA_XFER_STATUS_HALTED] = -EPIPE,
+ [WA_XFER_STATUS_DATA_BUFFER_ERROR] = -ENOBUFS,
+ [WA_XFER_STATUS_BABBLE] = -EOVERFLOW,
+ [WA_XFER_RESERVED] = EINVAL,
+ [WA_XFER_STATUS_NOT_FOUND] = 0,
+ [WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM,
+ [WA_XFER_STATUS_TRANSACTION_ERROR] = -EILSEQ,
+ [WA_XFER_STATUS_ABORTED] = -ENOENT,
+ [WA_XFER_STATUS_RPIPE_NOT_READY] = EINVAL,
+ [WA_XFER_INVALID_FORMAT] = EINVAL,
+ [WA_XFER_UNEXPECTED_SEGMENT_NUMBER] = EINVAL,
+ [WA_XFER_STATUS_RPIPE_TYPE_MISMATCH] = EINVAL,
+ };
+ status &= 0x3f;
+
+ if (status == 0)
+ return 0;
+ if (status >= ARRAY_SIZE(xlat)) {
+ printk_ratelimited(KERN_ERR "%s(): BUG? "
+ "Unknown WA transfer status 0x%02x\n",
+ __func__, real_status);
+ return -EINVAL;
+ }
+ errno = xlat[status];
+ if (unlikely(errno > 0)) {
+ printk_ratelimited(KERN_ERR "%s(): BUG? "
+ "Inconsistent WA status: 0x%02x\n",
+ __func__, real_status);
+ errno = -errno;
+ }
+ return errno;
+}
+
+/*
+ * If a last segment flag and/or a transfer result error is encountered,
+ * no other segment transfer results will be returned from the device.
+ * Mark the remaining submitted or pending xfers as completed so that
+ * the xfer will complete cleanly.
+ *
+ * xfer->lock must be held
+ *
+ */
+static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
+ int starting_index, enum wa_seg_status status)
+{
+ int index;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+ for (index = starting_index; index < xfer->segs_submitted; index++) {
+ struct wa_seg *current_seg = xfer->seg[index];
+
+ BUG_ON(current_seg == NULL);
+
+ switch (current_seg->status) {
+ case WA_SEG_SUBMITTED:
+ case WA_SEG_PENDING:
+ case WA_SEG_DTI_PENDING:
+ rpipe_avail_inc(rpipe);
+ /*
+ * do not increment RPIPE avail for the WA_SEG_DELAYED case
+ * since it has not been submitted to the RPIPE.
+ */
+ /* fall through */
+ case WA_SEG_DELAYED:
+ xfer->segs_done++;
+ current_seg->status = status;
+ break;
+ case WA_SEG_ABORTED:
+ break;
+ default:
+ WARN(1, "%s: xfer 0x%08X#%d. bad seg status = %d\n",
+ __func__, wa_xfer_id(xfer), index,
+ current_seg->status);
+ break;
+ }
+ }
+}
+
+/* Populate the given urb based on the current isoc transfer state. */
+static int __wa_populate_buf_in_urb_isoc(struct wahc *wa,
+ struct urb *buf_in_urb, struct wa_xfer *xfer, struct wa_seg *seg)
+{
+ int urb_start_frame = seg->isoc_frame_index + seg->isoc_frame_offset;
+ int seg_index, total_len = 0, urb_frame_index = urb_start_frame;
+ struct usb_iso_packet_descriptor *iso_frame_desc =
+ xfer->urb->iso_frame_desc;
+ const int dti_packet_size = usb_endpoint_maxp(wa->dti_epd);
+ int next_frame_contiguous;
+ struct usb_iso_packet_descriptor *iso_frame;
+
+ BUG_ON(buf_in_urb->status == -EINPROGRESS);
+
+ /*
+ * If the current frame actual_length is contiguous with the next frame
+ * and actual_length is a multiple of the DTI endpoint max packet size,
+ * combine the current frame with the next frame in a single URB. This
+ * reduces the number of URBs that must be submitted in that case.
+ */
+ seg_index = seg->isoc_frame_index;
+ do {
+ next_frame_contiguous = 0;
+
+ iso_frame = &iso_frame_desc[urb_frame_index];
+ total_len += iso_frame->actual_length;
+ ++urb_frame_index;
+ ++seg_index;
+
+ if (seg_index < seg->isoc_frame_count) {
+ struct usb_iso_packet_descriptor *next_iso_frame;
+
+ next_iso_frame = &iso_frame_desc[urb_frame_index];
+
+ if ((iso_frame->offset + iso_frame->actual_length) ==
+ next_iso_frame->offset)
+ next_frame_contiguous = 1;
+ }
+ } while (next_frame_contiguous
+ && ((iso_frame->actual_length % dti_packet_size) == 0));
+
+ /* this should always be 0 before a resubmit. */
+ buf_in_urb->num_mapped_sgs = 0;
+ buf_in_urb->transfer_dma = xfer->urb->transfer_dma +
+ iso_frame_desc[urb_start_frame].offset;
+ buf_in_urb->transfer_buffer_length = total_len;
+ buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ buf_in_urb->transfer_buffer = NULL;
+ buf_in_urb->sg = NULL;
+ buf_in_urb->num_sgs = 0;
+ buf_in_urb->context = seg;
+
+ /* return the number of frames included in this URB. */
+ return seg_index - seg->isoc_frame_index;
+}
+
+/* Populate the given urb based on the current transfer state. */
+static int wa_populate_buf_in_urb(struct urb *buf_in_urb, struct wa_xfer *xfer,
+ unsigned int seg_idx, unsigned int bytes_transferred)
+{
+ int result = 0;
+ struct wa_seg *seg = xfer->seg[seg_idx];
+
+ BUG_ON(buf_in_urb->status == -EINPROGRESS);
+ /* this should always be 0 before a resubmit. */
+ buf_in_urb->num_mapped_sgs = 0;
+
+ if (xfer->is_dma) {
+ buf_in_urb->transfer_dma = xfer->urb->transfer_dma
+ + (seg_idx * xfer->seg_size);
+ buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ buf_in_urb->transfer_buffer = NULL;
+ buf_in_urb->sg = NULL;
+ buf_in_urb->num_sgs = 0;
+ } else {
+ /* do buffer or SG processing. */
+ buf_in_urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
+
+ if (xfer->urb->transfer_buffer) {
+ buf_in_urb->transfer_buffer =
+ xfer->urb->transfer_buffer
+ + (seg_idx * xfer->seg_size);
+ buf_in_urb->sg = NULL;
+ buf_in_urb->num_sgs = 0;
+ } else {
+ /* allocate an SG list to store seg_size bytes
+ and copy the subset of the xfer->urb->sg
+ that matches the buffer subset we are
+ about to read. */
+ buf_in_urb->sg = wa_xfer_create_subset_sg(
+ xfer->urb->sg,
+ seg_idx * xfer->seg_size,
+ bytes_transferred,
+ &(buf_in_urb->num_sgs));
+
+ if (!(buf_in_urb->sg)) {
+ buf_in_urb->num_sgs = 0;
+ result = -ENOMEM;
+ }
+ buf_in_urb->transfer_buffer = NULL;
+ }
+ }
+ buf_in_urb->transfer_buffer_length = bytes_transferred;
+ buf_in_urb->context = seg;
+
+ return result;
+}
+
+/*
+ * Process a xfer result completion message
+ *
+ * inbound transfers: need to schedule a buf_in_urb read
+ *
+ * FIXME: this function needs to be broken up in parts
+ */
+static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer,
+ struct wa_xfer_result *xfer_result)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+ unsigned long flags;
+ unsigned int seg_idx;
+ struct wa_seg *seg;
+ struct wa_rpipe *rpipe;
+ unsigned done = 0;
+ u8 usb_status;
+ unsigned rpipe_ready = 0;
+ unsigned bytes_transferred = le32_to_cpu(xfer_result->dwTransferLength);
+ struct urb *buf_in_urb = &(wa->buf_in_urbs[0]);
+
+ spin_lock_irqsave(&xfer->lock, flags);
+ seg_idx = xfer_result->bTransferSegment & 0x7f;
+ if (unlikely(seg_idx >= xfer->segs))
+ goto error_bad_seg;
+ seg = xfer->seg[seg_idx];
+ rpipe = xfer->ep->hcpriv;
+ usb_status = xfer_result->bTransferStatus;
+ dev_dbg(dev, "xfer %p ID 0x%08X#%u: bTransferStatus 0x%02x (seg status %u)\n",
+ xfer, wa_xfer_id(xfer), seg_idx, usb_status, seg->status);
+ if (seg->status == WA_SEG_ABORTED
+ || seg->status == WA_SEG_ERROR) /* already handled */
+ goto segment_aborted;
+ if (seg->status == WA_SEG_SUBMITTED) /* ops, got here */
+ seg->status = WA_SEG_PENDING; /* before wa_seg{_dto}_cb() */
+ if (seg->status != WA_SEG_PENDING) {
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: Bad segment state %u\n",
+ xfer, seg_idx, seg->status);
+ seg->status = WA_SEG_PENDING; /* workaround/"fix" it */
+ }
+ if (usb_status & 0x80) {
+ seg->result = wa_xfer_status_to_errno(usb_status);
+ dev_err(dev, "DTI: xfer %p 0x%08X:#%u failed (0x%02x)\n",
+ xfer, xfer->id, seg->index, usb_status);
+ seg->status = ((usb_status & 0x7F) == WA_XFER_STATUS_ABORTED) ?
+ WA_SEG_ABORTED : WA_SEG_ERROR;
+ goto error_complete;
+ }
+ /* FIXME: we ignore warnings, tally them for stats */
+ if (usb_status & 0x40) /* Warning?... */
+ usb_status = 0; /* ... pass */
+ /*
+ * If the last segment bit is set, complete the remaining segments.
+ * When the current segment is completed, either in wa_buf_in_cb for
+ * transfers with data or below for no data, the xfer will complete.
+ */
+ if (xfer_result->bTransferSegment & 0x80)
+ wa_complete_remaining_xfer_segs(xfer, seg->index + 1,
+ WA_SEG_DONE);
+ if (usb_pipeisoc(xfer->urb->pipe)
+ && (le32_to_cpu(xfer_result->dwNumOfPackets) > 0)) {
+ /* set up WA state to read the isoc packet status next. */
+ wa->dti_isoc_xfer_in_progress = wa_xfer_id(xfer);
+ wa->dti_isoc_xfer_seg = seg_idx;
+ wa->dti_state = WA_DTI_ISOC_PACKET_STATUS_PENDING;
+ } else if (xfer->is_inbound && !usb_pipeisoc(xfer->urb->pipe)
+ && (bytes_transferred > 0)) {
+ /* IN data phase: read to buffer */
+ seg->status = WA_SEG_DTI_PENDING;
+ result = wa_populate_buf_in_urb(buf_in_urb, xfer, seg_idx,
+ bytes_transferred);
+ if (result < 0)
+ goto error_buf_in_populate;
+ ++(wa->active_buf_in_urbs);
+ result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
+ if (result < 0) {
+ --(wa->active_buf_in_urbs);
+ goto error_submit_buf_in;
+ }
+ } else {
+ /* OUT data phase or no data, complete it -- */
+ seg->result = bytes_transferred;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ return;
+
+error_submit_buf_in:
+ if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "DTI: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",
+ xfer, seg_idx, result);
+ seg->result = result;
+ kfree(buf_in_urb->sg);
+ buf_in_urb->sg = NULL;
+error_buf_in_populate:
+ __wa_xfer_abort(xfer);
+ seg->status = WA_SEG_ERROR;
+error_complete:
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ wa_complete_remaining_xfer_segs(xfer, seg->index + 1, seg->status);
+ done = __wa_xfer_is_done(xfer);
+ /*
+ * queue work item to clear STALL for control endpoints.
+ * Otherwise, let endpoint_reset take care of it.
+ */
+ if (((usb_status & 0x3f) == WA_XFER_STATUS_HALTED) &&
+ usb_endpoint_xfer_control(&xfer->ep->desc) &&
+ done) {
+
+ dev_info(dev, "Control EP stall. Queue delayed work.\n");
+ spin_lock(&wa->xfer_list_lock);
+ /* move xfer from xfer_list to xfer_errored_list. */
+ list_move_tail(&xfer->list_node, &wa->xfer_errored_list);
+ spin_unlock(&wa->xfer_list_lock);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ queue_work(wusbd, &wa->xfer_error_work);
+ } else {
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ }
+
+ return;
+
+error_bad_seg:
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_urb_dequeue(wa, xfer->urb, -ENOENT);
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx);
+ if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "DTI: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ return;
+
+segment_aborted:
+ /* nothing to do, as the aborter did the completion */
+ spin_unlock_irqrestore(&xfer->lock, flags);
+}
+
+/*
+ * Process a isochronous packet status message
+ *
+ * inbound transfers: need to schedule a buf_in_urb read
+ */
+static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb)
+{
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_xfer_packet_status_hwaiso *packet_status;
+ struct wa_xfer_packet_status_len_hwaiso *status_array;
+ struct wa_xfer *xfer;
+ unsigned long flags;
+ struct wa_seg *seg;
+ struct wa_rpipe *rpipe;
+ unsigned done = 0, dti_busy = 0, data_frame_count = 0, seg_index;
+ unsigned first_frame_index = 0, rpipe_ready = 0;
+ size_t expected_size;
+
+ /* We have a xfer result buffer; check it */
+ dev_dbg(dev, "DTI: isoc packet status %d bytes at %p\n",
+ urb->actual_length, urb->transfer_buffer);
+ packet_status = (struct wa_xfer_packet_status_hwaiso *)(wa->dti_buf);
+ if (packet_status->bPacketType != WA_XFER_ISO_PACKET_STATUS) {
+ dev_err(dev, "DTI Error: isoc packet status--bad type 0x%02x\n",
+ packet_status->bPacketType);
+ goto error_parse_buffer;
+ }
+ xfer = wa_xfer_get_by_id(wa, wa->dti_isoc_xfer_in_progress);
+ if (xfer == NULL) {
+ dev_err(dev, "DTI Error: isoc packet status--unknown xfer 0x%08x\n",
+ wa->dti_isoc_xfer_in_progress);
+ goto error_parse_buffer;
+ }
+ spin_lock_irqsave(&xfer->lock, flags);
+ if (unlikely(wa->dti_isoc_xfer_seg >= xfer->segs))
+ goto error_bad_seg;
+ seg = xfer->seg[wa->dti_isoc_xfer_seg];
+ rpipe = xfer->ep->hcpriv;
+ expected_size = struct_size(packet_status, PacketStatus,
+ seg->isoc_frame_count);
+ if (urb->actual_length != expected_size) {
+ dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %zu needed)\n",
+ urb->actual_length, expected_size);
+ goto error_bad_seg;
+ }
+ if (le16_to_cpu(packet_status->wLength) != expected_size) {
+ dev_err(dev, "DTI Error: isoc packet status--bad length %u\n",
+ le16_to_cpu(packet_status->wLength));
+ goto error_bad_seg;
+ }
+ /* write isoc packet status and lengths back to the xfer urb. */
+ status_array = packet_status->PacketStatus;
+ xfer->urb->start_frame =
+ wa->wusb->usb_hcd.driver->get_frame_number(&wa->wusb->usb_hcd);
+ for (seg_index = 0; seg_index < seg->isoc_frame_count; ++seg_index) {
+ struct usb_iso_packet_descriptor *iso_frame_desc =
+ xfer->urb->iso_frame_desc;
+ const int xfer_frame_index =
+ seg->isoc_frame_offset + seg_index;
+
+ iso_frame_desc[xfer_frame_index].status =
+ wa_xfer_status_to_errno(
+ le16_to_cpu(status_array[seg_index].PacketStatus));
+ iso_frame_desc[xfer_frame_index].actual_length =
+ le16_to_cpu(status_array[seg_index].PacketLength);
+ /* track the number of frames successfully transferred. */
+ if (iso_frame_desc[xfer_frame_index].actual_length > 0) {
+ /* save the starting frame index for buf_in_urb. */
+ if (!data_frame_count)
+ first_frame_index = seg_index;
+ ++data_frame_count;
+ }
+ }
+
+ if (xfer->is_inbound && data_frame_count) {
+ int result, total_frames_read = 0, urb_index = 0;
+ struct urb *buf_in_urb;
+
+ /* IN data phase: read to buffer */
+ seg->status = WA_SEG_DTI_PENDING;
+
+ /* start with the first frame with data. */
+ seg->isoc_frame_index = first_frame_index;
+ /* submit up to WA_MAX_BUF_IN_URBS read URBs. */
+ do {
+ int urb_frame_index, urb_frame_count;
+ struct usb_iso_packet_descriptor *iso_frame_desc;
+
+ buf_in_urb = &(wa->buf_in_urbs[urb_index]);
+ urb_frame_count = __wa_populate_buf_in_urb_isoc(wa,
+ buf_in_urb, xfer, seg);
+ /* advance frame index to start of next read URB. */
+ seg->isoc_frame_index += urb_frame_count;
+ total_frames_read += urb_frame_count;
+
+ ++(wa->active_buf_in_urbs);
+ result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
+
+ /* skip 0-byte frames. */
+ urb_frame_index =
+ seg->isoc_frame_offset + seg->isoc_frame_index;
+ iso_frame_desc =
+ &(xfer->urb->iso_frame_desc[urb_frame_index]);
+ while ((seg->isoc_frame_index <
+ seg->isoc_frame_count) &&
+ (iso_frame_desc->actual_length == 0)) {
+ ++(seg->isoc_frame_index);
+ ++iso_frame_desc;
+ }
+ ++urb_index;
+
+ } while ((result == 0) && (urb_index < WA_MAX_BUF_IN_URBS)
+ && (seg->isoc_frame_index <
+ seg->isoc_frame_count));
+
+ if (result < 0) {
+ --(wa->active_buf_in_urbs);
+ dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
+ result);
+ wa_reset_all(wa);
+ } else if (data_frame_count > total_frames_read)
+ /* If we need to read more frames, set DTI busy. */
+ dti_busy = 1;
+ } else {
+ /* OUT transfer or no more IN data, complete it -- */
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (dti_busy)
+ wa->dti_state = WA_DTI_BUF_IN_DATA_PENDING;
+ else
+ wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ wa_xfer_put(xfer);
+ return dti_busy;
+
+error_bad_seg:
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_xfer_put(xfer);
+error_parse_buffer:
+ return dti_busy;
+}
+
+/*
+ * Callback for the IN data phase
+ *
+ * If successful transition state; otherwise, take a note of the
+ * error, mark this segment done and try completion.
+ *
+ * Note we don't access until we are sure that the transfer hasn't
+ * been cancelled (ECONNRESET, ENOENT), which could mean that
+ * seg->xfer could be already gone.
+ */
+static void wa_buf_in_cb(struct urb *urb)
+{
+ struct wa_seg *seg = urb->context;
+ struct wa_xfer *xfer = seg->xfer;
+ struct wahc *wa;
+ struct device *dev;
+ struct wa_rpipe *rpipe;
+ unsigned rpipe_ready = 0, isoc_data_frame_count = 0;
+ unsigned long flags;
+ int resubmit_dti = 0, active_buf_in_urbs;
+ u8 done = 0;
+
+ /* free the sg if it was used. */
+ kfree(urb->sg);
+ urb->sg = NULL;
+
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ --(wa->active_buf_in_urbs);
+ active_buf_in_urbs = wa->active_buf_in_urbs;
+ rpipe = xfer->ep->hcpriv;
+
+ if (usb_pipeisoc(xfer->urb->pipe)) {
+ struct usb_iso_packet_descriptor *iso_frame_desc =
+ xfer->urb->iso_frame_desc;
+ int seg_index;
+
+ /*
+ * Find the next isoc frame with data and count how many
+ * frames with data remain.
+ */
+ seg_index = seg->isoc_frame_index;
+ while (seg_index < seg->isoc_frame_count) {
+ const int urb_frame_index =
+ seg->isoc_frame_offset + seg_index;
+
+ if (iso_frame_desc[urb_frame_index].actual_length > 0) {
+ /* save the index of the next frame with data */
+ if (!isoc_data_frame_count)
+ seg->isoc_frame_index = seg_index;
+ ++isoc_data_frame_count;
+ }
+ ++seg_index;
+ }
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+
+ switch (urb->status) {
+ case 0:
+ spin_lock_irqsave(&xfer->lock, flags);
+
+ seg->result += urb->actual_length;
+ if (isoc_data_frame_count > 0) {
+ int result, urb_frame_count;
+
+ /* submit a read URB for the next frame with data. */
+ urb_frame_count = __wa_populate_buf_in_urb_isoc(wa, urb,
+ xfer, seg);
+ /* advance index to start of next read URB. */
+ seg->isoc_frame_index += urb_frame_count;
+ ++(wa->active_buf_in_urbs);
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result < 0) {
+ --(wa->active_buf_in_urbs);
+ dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
+ result);
+ wa_reset_all(wa);
+ }
+ /*
+ * If we are in this callback and
+ * isoc_data_frame_count > 0, it means that the dti_urb
+ * submission was delayed in wa_dti_cb. Once
+ * we submit the last buf_in_urb, we can submit the
+ * delayed dti_urb.
+ */
+ resubmit_dti = (isoc_data_frame_count ==
+ urb_frame_count);
+ } else if (active_buf_in_urbs == 0) {
+ dev_dbg(dev,
+ "xfer %p 0x%08X#%u: data in done (%zu bytes)\n",
+ xfer, wa_xfer_id(xfer), seg->index,
+ seg->result);
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg,
+ WA_SEG_DONE);
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ break;
+ case -ECONNRESET: /* URB unlinked; no need to do anything */
+ case -ENOENT: /* as it was done by the who unlinked us */
+ break;
+ default: /* Other errors ... */
+ /*
+ * Error on data buf read. Only resubmit DTI if it hasn't
+ * already been done by previously hitting this error or by a
+ * successful completion of the previous buf_in_urb.
+ */
+ resubmit_dti = wa->dti_state != WA_DTI_TRANSFER_RESULT_PENDING;
+ spin_lock_irqsave(&xfer->lock, flags);
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p 0x%08X#%u: data in error %d\n",
+ xfer, wa_xfer_id(xfer), seg->index,
+ urb->status);
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)){
+ dev_err(dev, "DTO: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ seg->result = urb->status;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ if (active_buf_in_urbs == 0)
+ done = __wa_xfer_mark_seg_as_done(xfer, seg,
+ WA_SEG_ERROR);
+ else
+ __wa_xfer_abort(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ }
+
+ if (resubmit_dti) {
+ int result;
+
+ wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
+
+ result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
+ result);
+ wa_reset_all(wa);
+ }
+ }
+}
+
+/*
+ * Handle an incoming transfer result buffer
+ *
+ * Given a transfer result buffer, it completes the transfer (possibly
+ * scheduling and buffer in read) and then resubmits the DTI URB for a
+ * new transfer result read.
+ *
+ *
+ * The xfer_result DTI URB state machine
+ *
+ * States: OFF | RXR (Read-Xfer-Result) | RBI (Read-Buffer-In)
+ *
+ * We start in OFF mode, the first xfer_result notification [through
+ * wa_handle_notif_xfer()] moves us to RXR by posting the DTI-URB to
+ * read.
+ *
+ * We receive a buffer -- if it is not a xfer_result, we complain and
+ * repost the DTI-URB. If it is a xfer_result then do the xfer seg
+ * request accounting. If it is an IN segment, we move to RBI and post
+ * a BUF-IN-URB to the right buffer. The BUF-IN-URB callback will
+ * repost the DTI-URB and move to RXR state. if there was no IN
+ * segment, it will repost the DTI-URB.
+ *
+ * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many
+ * errors) in the URBs.
+ */
+static void wa_dti_cb(struct urb *urb)
+{
+ int result, dti_busy = 0;
+ struct wahc *wa = urb->context;
+ struct device *dev = &wa->usb_iface->dev;
+ u32 xfer_id;
+ u8 usb_status;
+
+ BUG_ON(wa->dti_urb != urb);
+ switch (wa->dti_urb->status) {
+ case 0:
+ if (wa->dti_state == WA_DTI_TRANSFER_RESULT_PENDING) {
+ struct wa_xfer_result *xfer_result;
+ struct wa_xfer *xfer;
+
+ /* We have a xfer result buffer; check it */
+ dev_dbg(dev, "DTI: xfer result %d bytes at %p\n",
+ urb->actual_length, urb->transfer_buffer);
+ if (urb->actual_length != sizeof(*xfer_result)) {
+ dev_err(dev, "DTI Error: xfer result--bad size xfer result (%d bytes vs %zu needed)\n",
+ urb->actual_length,
+ sizeof(*xfer_result));
+ break;
+ }
+ xfer_result = (struct wa_xfer_result *)(wa->dti_buf);
+ if (xfer_result->hdr.bLength != sizeof(*xfer_result)) {
+ dev_err(dev, "DTI Error: xfer result--bad header length %u\n",
+ xfer_result->hdr.bLength);
+ break;
+ }
+ if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) {
+ dev_err(dev, "DTI Error: xfer result--bad header type 0x%02x\n",
+ xfer_result->hdr.bNotifyType);
+ break;
+ }
+ xfer_id = le32_to_cpu(xfer_result->dwTransferID);
+ usb_status = xfer_result->bTransferStatus & 0x3f;
+ if (usb_status == WA_XFER_STATUS_NOT_FOUND) {
+ /* taken care of already */
+ dev_dbg(dev, "%s: xfer 0x%08X#%u not found.\n",
+ __func__, xfer_id,
+ xfer_result->bTransferSegment & 0x7f);
+ break;
+ }
+ xfer = wa_xfer_get_by_id(wa, xfer_id);
+ if (xfer == NULL) {
+ /* FIXME: transaction not found. */
+ dev_err(dev, "DTI Error: xfer result--unknown xfer 0x%08x (status 0x%02x)\n",
+ xfer_id, usb_status);
+ break;
+ }
+ wa_xfer_result_chew(wa, xfer, xfer_result);
+ wa_xfer_put(xfer);
+ } else if (wa->dti_state == WA_DTI_ISOC_PACKET_STATUS_PENDING) {
+ dti_busy = wa_process_iso_packet_status(wa, urb);
+ } else {
+ dev_err(dev, "DTI Error: unexpected EP state = %d\n",
+ wa->dti_state);
+ }
+ break;
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ case -ESHUTDOWN: /* going away! */
+ dev_dbg(dev, "DTI: going down! %d\n", urb->status);
+ goto out;
+ default:
+ /* Unknown error */
+ if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "DTI: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ goto out;
+ }
+ if (printk_ratelimit())
+ dev_err(dev, "DTI: URB error %d\n", urb->status);
+ break;
+ }
+
+ /* Resubmit the DTI URB if we are not busy processing isoc in frames. */
+ if (!dti_busy) {
+ result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
+ result);
+ wa_reset_all(wa);
+ }
+ }
+out:
+ return;
+}
+
+/*
+ * Initialize the DTI URB for reading transfer result notifications and also
+ * the buffer-in URB, for reading buffers. Then we just submit the DTI URB.
+ */
+int wa_dti_start(struct wahc *wa)
+{
+ const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
+ struct device *dev = &wa->usb_iface->dev;
+ int result = -ENOMEM, index;
+
+ if (wa->dti_urb != NULL) /* DTI URB already started */
+ goto out;
+
+ wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (wa->dti_urb == NULL)
+ goto error_dti_urb_alloc;
+ usb_fill_bulk_urb(
+ wa->dti_urb, wa->usb_dev,
+ usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress),
+ wa->dti_buf, wa->dti_buf_size,
+ wa_dti_cb, wa);
+
+ /* init the buf in URBs */
+ for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) {
+ usb_fill_bulk_urb(
+ &(wa->buf_in_urbs[index]), wa->usb_dev,
+ usb_rcvbulkpipe(wa->usb_dev,
+ 0x80 | dti_epd->bEndpointAddress),
+ NULL, 0, wa_buf_in_cb, wa);
+ }
+ result = usb_submit_urb(wa->dti_urb, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "DTI Error: Could not submit DTI URB (%d) resetting\n",
+ result);
+ goto error_dti_urb_submit;
+ }
+out:
+ return 0;
+
+error_dti_urb_submit:
+ usb_put_urb(wa->dti_urb);
+ wa->dti_urb = NULL;
+error_dti_urb_alloc:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wa_dti_start);
+/*
+ * Transfer complete notification
+ *
+ * Called from the notif.c code. We get a notification on EP2 saying
+ * that some endpoint has some transfer result data available. We are
+ * about to read it.
+ *
+ * To speed up things, we always have a URB reading the DTI URB; we
+ * don't really set it up and start it until the first xfer complete
+ * notification arrives, which is what we do here.
+ *
+ * Follow up in wa_dti_cb(), as that's where the whole state
+ * machine starts.
+ *
+ * @wa shall be referenced
+ */
+void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
+{
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_notif_xfer *notif_xfer;
+ const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
+
+ notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr);
+ BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER);
+
+ if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) {
+ /* FIXME: hardcoded limitation, adapt */
+ dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n",
+ notif_xfer->bEndpoint, dti_epd->bEndpointAddress);
+ goto error;
+ }
+
+ /* attempt to start the DTI ep processing. */
+ if (wa_dti_start(wa) < 0)
+ goto error;
+
+ return;
+
+error:
+ wa_reset_all(wa);
+}
diff --git a/drivers/staging/wusbcore/wusbhc.c b/drivers/staging/wusbcore/wusbhc.c
new file mode 100644
index 000000000000..d0b404d258e8
--- /dev/null
+++ b/drivers/staging/wusbcore/wusbhc.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * sysfs glue, wusbcore module support and life cycle management
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Creation/destruction of wusbhc is split in two parts; that that
+ * doesn't require the HCD to be added (wusbhc_{create,destroy}) and
+ * the one that requires (phase B, wusbhc_b_{create,destroy}).
+ *
+ * This is so because usb_add_hcd() will start the HC, and thus, all
+ * the HC specific stuff has to be already initialized (like sysfs
+ * thingies).
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include "wusbhc.h"
+
+/**
+ * Extract the wusbhc that corresponds to a USB Host Controller class device
+ *
+ * WARNING! Apply only if @dev is that of a
+ * wusbhc.usb_hcd.self->class_dev; otherwise, you loose.
+ */
+static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev)
+{
+ struct usb_bus *usb_bus = dev_get_drvdata(dev);
+ struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus);
+ return usb_hcd_to_wusbhc(usb_hcd);
+}
+
+/*
+ * Show & store the current WUSB trust timeout
+ *
+ * We don't do locking--it is an 'atomic' value.
+ *
+ * The units that we store/show are always MILLISECONDS. However, the
+ * value of trust_timeout is jiffies.
+ */
+static ssize_t wusb_trust_timeout_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout);
+}
+
+static ssize_t wusb_trust_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ ssize_t result = -ENOSYS;
+ unsigned trust_timeout;
+
+ result = sscanf(buf, "%u", &trust_timeout);
+ if (result != 1) {
+ result = -EINVAL;
+ goto out;
+ }
+ wusbhc->trust_timeout = min_t(unsigned, trust_timeout, 500);
+ cancel_delayed_work(&wusbhc->keep_alive_timer);
+ flush_workqueue(wusbd);
+ queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+ msecs_to_jiffies(wusbhc->trust_timeout / 2));
+out:
+ return result < 0 ? result : size;
+}
+static DEVICE_ATTR_RW(wusb_trust_timeout);
+
+/*
+ * Show the current WUSB CHID.
+ */
+static ssize_t wusb_chid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ const struct wusb_ckhdid *chid;
+
+ if (wusbhc->wuie_host_info != NULL)
+ chid = &wusbhc->wuie_host_info->CHID;
+ else
+ chid = &wusb_ckhdid_zero;
+
+ return sprintf(buf, "%16ph\n", chid->data);
+}
+
+/*
+ * Store a new CHID.
+ *
+ * - Write an all zeros CHID and it will stop the controller
+ * - Write a non-zero CHID and it will start it.
+ *
+ * See wusbhc_chid_set() for more info.
+ */
+static ssize_t wusb_chid_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ struct wusb_ckhdid chid;
+ ssize_t result;
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx\n",
+ &chid.data[0] , &chid.data[1] ,
+ &chid.data[2] , &chid.data[3] ,
+ &chid.data[4] , &chid.data[5] ,
+ &chid.data[6] , &chid.data[7] ,
+ &chid.data[8] , &chid.data[9] ,
+ &chid.data[10], &chid.data[11],
+ &chid.data[12], &chid.data[13],
+ &chid.data[14], &chid.data[15]);
+ if (result != 16) {
+ dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): "
+ "%d\n", (int)result);
+ return -EINVAL;
+ }
+ result = wusbhc_chid_set(wusbhc, &chid);
+ return result < 0 ? result : size;
+}
+static DEVICE_ATTR_RW(wusb_chid);
+
+
+static ssize_t wusb_phy_rate_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+ return sprintf(buf, "%d\n", wusbhc->phy_rate);
+}
+
+static ssize_t wusb_phy_rate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ uint8_t phy_rate;
+ ssize_t result;
+
+ result = sscanf(buf, "%hhu", &phy_rate);
+ if (result != 1)
+ return -EINVAL;
+ if (phy_rate >= UWB_PHY_RATE_INVALID)
+ return -EINVAL;
+
+ wusbhc->phy_rate = phy_rate;
+ return size;
+}
+static DEVICE_ATTR_RW(wusb_phy_rate);
+
+static ssize_t wusb_dnts_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+ return sprintf(buf, "num slots: %d\ninterval: %dms\n",
+ wusbhc->dnts_num_slots, wusbhc->dnts_interval);
+}
+
+static ssize_t wusb_dnts_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ uint8_t num_slots, interval;
+ ssize_t result;
+
+ result = sscanf(buf, "%hhu %hhu", &num_slots, &interval);
+
+ if (result != 2)
+ return -EINVAL;
+
+ wusbhc->dnts_num_slots = num_slots;
+ wusbhc->dnts_interval = interval;
+
+ return size;
+}
+static DEVICE_ATTR_RW(wusb_dnts);
+
+static ssize_t wusb_retry_count_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+ return sprintf(buf, "%d\n", wusbhc->retry_count);
+}
+
+static ssize_t wusb_retry_count_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ uint8_t retry_count;
+ ssize_t result;
+
+ result = sscanf(buf, "%hhu", &retry_count);
+
+ if (result != 1)
+ return -EINVAL;
+
+ wusbhc->retry_count = max_t(uint8_t, retry_count,
+ WUSB_RETRY_COUNT_MAX);
+
+ return size;
+}
+static DEVICE_ATTR_RW(wusb_retry_count);
+
+/* Group all the WUSBHC attributes */
+static struct attribute *wusbhc_attrs[] = {
+ &dev_attr_wusb_trust_timeout.attr,
+ &dev_attr_wusb_chid.attr,
+ &dev_attr_wusb_phy_rate.attr,
+ &dev_attr_wusb_dnts.attr,
+ &dev_attr_wusb_retry_count.attr,
+ NULL,
+};
+
+static const struct attribute_group wusbhc_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = wusbhc_attrs,
+};
+
+/*
+ * Create a wusbhc instance
+ *
+ * NOTEs:
+ *
+ * - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been
+ * initialized but not added.
+ *
+ * - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling.
+ *
+ * - fill out wusbhc->uwb_rc and refcount it before calling
+ * - fill out the wusbhc->sec_modes array
+ */
+int wusbhc_create(struct wusbhc *wusbhc)
+{
+ int result = 0;
+
+ /* set defaults. These can be overwritten using sysfs attributes. */
+ wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;
+ wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1;
+ wusbhc->dnts_num_slots = 4;
+ wusbhc->dnts_interval = 2;
+ wusbhc->retry_count = WUSB_RETRY_COUNT_INFINITE;
+
+ mutex_init(&wusbhc->mutex);
+ result = wusbhc_mmcie_create(wusbhc);
+ if (result < 0)
+ goto error_mmcie_create;
+ result = wusbhc_devconnect_create(wusbhc);
+ if (result < 0)
+ goto error_devconnect_create;
+ result = wusbhc_rh_create(wusbhc);
+ if (result < 0)
+ goto error_rh_create;
+ result = wusbhc_sec_create(wusbhc);
+ if (result < 0)
+ goto error_sec_create;
+ return 0;
+
+error_sec_create:
+ wusbhc_rh_destroy(wusbhc);
+error_rh_create:
+ wusbhc_devconnect_destroy(wusbhc);
+error_devconnect_create:
+ wusbhc_mmcie_destroy(wusbhc);
+error_mmcie_create:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_create);
+
+static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc)
+{
+ return &wusbhc->usb_hcd.self.controller->kobj;
+}
+
+/*
+ * Phase B of a wusbhc instance creation
+ *
+ * Creates fields that depend on wusbhc->usb_hcd having been
+ * added. This is where we create the sysfs files in
+ * /sys/class/usb_host/usb_hostX/.
+ *
+ * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper
+ * layer (hwahc or whci)
+ */
+int wusbhc_b_create(struct wusbhc *wusbhc)
+{
+ int result = 0;
+ struct device *dev = wusbhc->usb_hcd.self.controller;
+
+ result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
+ if (result < 0) {
+ dev_err(dev, "Cannot register WUSBHC attributes: %d\n",
+ result);
+ goto error_create_attr_group;
+ }
+
+ return 0;
+error_create_attr_group:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_b_create);
+
+void wusbhc_b_destroy(struct wusbhc *wusbhc)
+{
+ wusbhc_pal_unregister(wusbhc);
+ sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
+}
+EXPORT_SYMBOL_GPL(wusbhc_b_destroy);
+
+void wusbhc_destroy(struct wusbhc *wusbhc)
+{
+ wusbhc_sec_destroy(wusbhc);
+ wusbhc_rh_destroy(wusbhc);
+ wusbhc_devconnect_destroy(wusbhc);
+ wusbhc_mmcie_destroy(wusbhc);
+}
+EXPORT_SYMBOL_GPL(wusbhc_destroy);
+
+struct workqueue_struct *wusbd;
+EXPORT_SYMBOL_GPL(wusbd);
+
+/*
+ * WUSB Cluster ID allocation map
+ *
+ * Each WUSB bus in a channel is identified with a Cluster Id in the
+ * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff
+ * (that's space for 31 WUSB controllers, as 0xff can't be taken). We
+ * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff).
+ *
+ * For each one we taken, we pin it in the bitap
+ */
+#define CLUSTER_IDS 32
+static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS);
+static DEFINE_SPINLOCK(wusb_cluster_ids_lock);
+
+/*
+ * Get a WUSB Cluster ID
+ *
+ * Need to release with wusb_cluster_id_put() when done w/ it.
+ */
+/* FIXME: coordinate with the choose_addres() from the USB stack */
+/* we want to leave the top of the 128 range for cluster addresses and
+ * the bottom for device addresses (as we map them one on one with
+ * ports). */
+u8 wusb_cluster_id_get(void)
+{
+ u8 id;
+ spin_lock(&wusb_cluster_ids_lock);
+ id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS);
+ if (id >= CLUSTER_IDS) {
+ id = 0;
+ goto out;
+ }
+ set_bit(id, wusb_cluster_id_table);
+ id = (u8) 0xff - id;
+out:
+ spin_unlock(&wusb_cluster_ids_lock);
+ return id;
+
+}
+EXPORT_SYMBOL_GPL(wusb_cluster_id_get);
+
+/*
+ * Release a WUSB Cluster ID
+ *
+ * Obtained it with wusb_cluster_id_get()
+ */
+void wusb_cluster_id_put(u8 id)
+{
+ id = 0xff - id;
+ BUG_ON(id >= CLUSTER_IDS);
+ spin_lock(&wusb_cluster_ids_lock);
+ WARN_ON(!test_bit(id, wusb_cluster_id_table));
+ clear_bit(id, wusb_cluster_id_table);
+ spin_unlock(&wusb_cluster_ids_lock);
+}
+EXPORT_SYMBOL_GPL(wusb_cluster_id_put);
+
+/**
+ * wusbhc_giveback_urb - return an URB to the USB core
+ * @wusbhc: the host controller the URB is from.
+ * @urb: the URB.
+ * @status: the URB's status.
+ *
+ * Return an URB to the USB core doing some additional WUSB specific
+ * processing.
+ *
+ * - After a successful transfer, update the trust timeout timestamp
+ * for the WUSB device.
+ *
+ * - [WUSB] sections 4.13 and 7.5.1 specify the stop retransmission
+ * condition for the WCONNECTACK_IE is that the host has observed
+ * the associated device responding to a control transfer.
+ */
+void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status)
+{
+ struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc,
+ urb->dev);
+
+ if (status == 0 && wusb_dev) {
+ wusb_dev->entry_ts = jiffies;
+
+ /* wusbhc_devconnect_acked() can't be called from
+ atomic context so defer it to a work queue. */
+ if (!list_empty(&wusb_dev->cack_node))
+ queue_work(wusbd, &wusb_dev->devconnect_acked_work);
+ else
+ wusb_dev_put(wusb_dev);
+ }
+
+ usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status);
+}
+EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
+
+/**
+ * wusbhc_reset_all - reset the HC hardware
+ * @wusbhc: the host controller to reset.
+ *
+ * Request a full hardware reset of the chip. This will also reset
+ * the radio controller and any other PALs.
+ */
+void wusbhc_reset_all(struct wusbhc *wusbhc)
+{
+ if (wusbhc->uwb_rc)
+ uwb_rc_reset_all(wusbhc->uwb_rc);
+}
+EXPORT_SYMBOL_GPL(wusbhc_reset_all);
+
+static struct notifier_block wusb_usb_notifier = {
+ .notifier_call = wusb_usb_ncb,
+ .priority = INT_MAX /* Need to be called first of all */
+};
+
+static int __init wusbcore_init(void)
+{
+ int result;
+ result = wusb_crypto_init();
+ if (result < 0)
+ goto error_crypto_init;
+ /* WQ is singlethread because we need to serialize notifications */
+ wusbd = create_singlethread_workqueue("wusbd");
+ if (wusbd == NULL) {
+ result = -ENOMEM;
+ printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n");
+ goto error_wusbd_create;
+ }
+ usb_register_notify(&wusb_usb_notifier);
+ bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS);
+ set_bit(0, wusb_cluster_id_table); /* reserve Cluster ID 0xff */
+ return 0;
+
+error_wusbd_create:
+ wusb_crypto_exit();
+error_crypto_init:
+ return result;
+
+}
+module_init(wusbcore_init);
+
+static void __exit wusbcore_exit(void)
+{
+ clear_bit(0, wusb_cluster_id_table);
+ if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) {
+ printk(KERN_ERR "BUG: WUSB Cluster IDs not released on exit: %*pb\n",
+ CLUSTER_IDS, wusb_cluster_id_table);
+ WARN_ON(1);
+ }
+ usb_unregister_notify(&wusb_usb_notifier);
+ destroy_workqueue(wusbd);
+ wusb_crypto_exit();
+}
+module_exit(wusbcore_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/wusbhc.h b/drivers/staging/wusbcore/wusbhc.h
new file mode 100644
index 000000000000..716244a2ec44
--- /dev/null
+++ b/drivers/staging/wusbcore/wusbhc.h
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * Common infrastructure for WHCI and HWA WUSB-HC drivers
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This driver implements parts common to all Wireless USB Host
+ * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used
+ * by:
+ *
+ * - hwahc: HWA, USB-dongle that implements a Wireless USB host
+ * controller, (Wireless USB 1.0 Host-Wire-Adapter specification).
+ *
+ * - whci: WHCI, a PCI card with a wireless host controller
+ * (Wireless Host Controller Interface 1.0 specification).
+ *
+ * Check out the Design-overview.txt file in the source documentation
+ * for other details on the implementation.
+ *
+ * Main blocks:
+ *
+ * rh Root Hub emulation (part of the HCD glue)
+ *
+ * devconnect Handle all the issues related to device connection,
+ * authentication, disconnection, timeout, reseting,
+ * keepalives, etc.
+ *
+ * mmc MMC IE broadcasting handling
+ *
+ * A host controller driver just initializes its stuff and as part of
+ * that, creates a 'struct wusbhc' instance that handles all the
+ * common WUSB mechanisms. Links in the function ops that are specific
+ * to it and then registers the host controller. Ready to run.
+ */
+
+#ifndef __WUSBHC_H__
+#define __WUSBHC_H__
+
+#include <linux/usb.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/kref.h>
+#include <linux/workqueue.h>
+#include <linux/usb/hcd.h>
+#include "../uwb/uwb.h"
+#include "include/wusb.h"
+
+/*
+ * Time from a WUSB channel stop request to the last transmitted MMC.
+ *
+ * This needs to be > 4.096 ms in case no MMCs can be transmitted in
+ * zone 0.
+ */
+#define WUSB_CHANNEL_STOP_DELAY_MS 8
+#define WUSB_RETRY_COUNT_MAX 15
+#define WUSB_RETRY_COUNT_INFINITE 0
+
+/**
+ * Wireless USB device
+ *
+ * Describe a WUSB device connected to the cluster. This struct
+ * belongs to the 'struct wusb_port' it is attached to and it is
+ * responsible for putting and clearing the pointer to it.
+ *
+ * Note this "complements" the 'struct usb_device' that the usb_hcd
+ * keeps for each connected USB device. However, it extends some
+ * information that is not available (there is no hcpriv ptr in it!)
+ * *and* most importantly, it's life cycle is different. It is created
+ * as soon as we get a DN_Connect (connect request notification) from
+ * the device through the WUSB host controller; the USB stack doesn't
+ * create the device until we authenticate it. FIXME: this will
+ * change.
+ *
+ * @bos: This is allocated when the BOS descriptors are read from
+ * the device and freed upon the wusb_dev struct dying.
+ * @wusb_cap_descr: points into @bos, and has been verified to be size
+ * safe.
+ */
+struct wusb_dev {
+ struct kref refcnt;
+ struct wusbhc *wusbhc;
+ struct list_head cack_node; /* Connect-Ack list */
+ struct list_head rekey_node; /* GTK rekey list */
+ u8 port_idx;
+ u8 addr;
+ u8 beacon_type:4;
+ struct usb_encryption_descriptor ccm1_etd;
+ struct wusb_ckhdid cdid;
+ unsigned long entry_ts;
+ struct usb_bos_descriptor *bos;
+ struct usb_wireless_cap_descriptor *wusb_cap_descr;
+ struct uwb_mas_bm availability;
+ struct work_struct devconnect_acked_work;
+ struct usb_device *usb_dev;
+};
+
+#define WUSB_DEV_ADDR_UNAUTH 0x80
+
+static inline void wusb_dev_init(struct wusb_dev *wusb_dev)
+{
+ kref_init(&wusb_dev->refcnt);
+ /* no need to init the cack_node */
+}
+
+extern void wusb_dev_destroy(struct kref *_wusb_dev);
+
+static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev)
+{
+ kref_get(&wusb_dev->refcnt);
+ return wusb_dev;
+}
+
+static inline void wusb_dev_put(struct wusb_dev *wusb_dev)
+{
+ kref_put(&wusb_dev->refcnt, wusb_dev_destroy);
+}
+
+/**
+ * Wireless USB Host Controller root hub "fake" ports
+ * (state and device information)
+ *
+ * Wireless USB is wireless, so there are no ports; but we
+ * fake'em. Each RC can connect a max of devices at the same time
+ * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's
+ * caps), referred to in wusbhc->ports_max.
+ *
+ * See rh.c for more information.
+ *
+ * The @status and @change use the same bits as in USB2.0[11.24.2.7],
+ * so we don't have to do much when getting the port's status.
+ *
+ * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10],
+ * include/linux/usb_ch9.h (#define USB_PORT_STAT_*)
+ */
+struct wusb_port {
+ u16 status;
+ u16 change;
+ struct wusb_dev *wusb_dev; /* connected device's info */
+ u32 ptk_tkid;
+};
+
+/**
+ * WUSB Host Controller specifics
+ *
+ * All fields that are common to all Wireless USB controller types
+ * (HWA and WHCI) are grouped here. Host Controller
+ * functions/operations that only deal with general Wireless USB HC
+ * issues use this data type to refer to the host.
+ *
+ * @usb_hcd Instantiation of a USB host controller
+ * (initialized by upper layer [HWA=HC or WHCI].
+ *
+ * @dev Device that implements this; initialized by the
+ * upper layer (HWA-HC, WHCI...); this device should
+ * have a refcount.
+ *
+ * @trust_timeout After this time without hearing for device
+ * activity, we consider the device gone and we have to
+ * re-authenticate.
+ *
+ * Can be accessed w/o locking--however, read to a
+ * local variable then use.
+ *
+ * @chid WUSB Cluster Host ID: this is supposed to be a
+ * unique value that doesn't change across reboots (so
+ * that your devices do not require re-association).
+ *
+ * Read/Write protected by @mutex
+ *
+ * @dev_info This array has ports_max elements. It is used to
+ * give the HC information about the WUSB devices (see
+ * 'struct wusb_dev_info').
+ *
+ * For HWA we need to allocate it in heap; for WHCI it
+ * needs to be permanently mapped, so we keep it for
+ * both and make it easy. Call wusbhc->dev_info_set()
+ * to update an entry.
+ *
+ * @ports_max Number of simultaneous device connections (fake
+ * ports) this HC will take. Read-only.
+ *
+ * @port Array of port status for each fake root port. Guaranteed to
+ * always be the same length during device existence
+ * [this allows for some unlocked but referenced reading].
+ *
+ * @mmcies_max Max number of Information Elements this HC can send
+ * in its MMC. Read-only.
+ *
+ * @start Start the WUSB channel.
+ *
+ * @stop Stop the WUSB channel after the specified number of
+ * milliseconds. Channel Stop IEs should be transmitted
+ * as required by [WUSB] 4.16.2.1.
+ *
+ * @mmcie_add HC specific operation (WHCI or HWA) for adding an
+ * MMCIE.
+ *
+ * @mmcie_rm HC specific operation (WHCI or HWA) for removing an
+ * MMCIE.
+ *
+ * @set_ptk: Set the PTK and enable encryption for a device. Or, if
+ * the supplied key is NULL, disable encryption for that
+ * device.
+ *
+ * @set_gtk: Set the GTK to be used for all future broadcast packets
+ * (i.e., MMCs). With some hardware, setting the GTK may start
+ * MMC transmission.
+ *
+ * NOTE:
+ *
+ * - If wusb_dev->usb_dev is not NULL, then usb_dev is valid
+ * (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev
+ * is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a
+ * refcount on it).
+ *
+ * Most of the times when you need to use it, it will be non-NULL,
+ * so there is no real need to check for it (wusb_dev will
+ * disappear before usb_dev).
+ *
+ * - The following fields need to be filled out before calling
+ * wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}.
+ *
+ * - there is no wusbhc_init() method, we do everything in
+ * wusbhc_create().
+ *
+ * - Creation is done in two phases, wusbhc_create() and
+ * wusbhc_create_b(); b are the parts that need to be called after
+ * calling usb_hcd_add(&wusbhc->usb_hcd).
+ */
+struct wusbhc {
+ struct usb_hcd usb_hcd; /* HAS TO BE 1st */
+ struct device *dev;
+ struct uwb_rc *uwb_rc;
+ struct uwb_pal pal;
+
+ unsigned trust_timeout; /* in jiffies */
+ struct wusb_ckhdid chid;
+ uint8_t phy_rate;
+ uint8_t dnts_num_slots;
+ uint8_t dnts_interval;
+ uint8_t retry_count;
+ struct wuie_host_info *wuie_host_info;
+
+ struct mutex mutex; /* locks everything else */
+ u16 cluster_id; /* Wireless USB Cluster ID */
+ struct wusb_port *port; /* Fake port status handling */
+ struct wusb_dev_info *dev_info; /* for Set Device Info mgmt */
+ u8 ports_max;
+ unsigned active:1; /* currently xmit'ing MMCs */
+ struct wuie_keep_alive keep_alive_ie; /* protected by mutex */
+ struct delayed_work keep_alive_timer;
+ struct list_head cack_list; /* Connect acknowledging */
+ size_t cack_count; /* protected by 'mutex' */
+ struct wuie_connect_ack cack_ie;
+ struct uwb_rsv *rsv; /* cluster bandwidth reservation */
+
+ struct mutex mmcie_mutex; /* MMC WUIE handling */
+ struct wuie_hdr **mmcie; /* WUIE array */
+ u8 mmcies_max;
+ /* FIXME: make wusbhc_ops? */
+ int (*start)(struct wusbhc *wusbhc);
+ void (*stop)(struct wusbhc *wusbhc, int delay);
+ int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+ u8 handle, struct wuie_hdr *wuie);
+ int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle);
+ int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev);
+ int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index,
+ const struct uwb_mas_bm *);
+ int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx,
+ u32 tkid, const void *key, size_t key_size);
+ int (*set_gtk)(struct wusbhc *wusbhc,
+ u32 tkid, const void *key, size_t key_size);
+ int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots);
+
+ struct {
+ struct usb_key_descriptor descr;
+ u8 data[16]; /* GTK key data */
+ } __attribute__((packed)) gtk;
+ u8 gtk_index;
+ u32 gtk_tkid;
+
+ /* workqueue for WUSB security related tasks. */
+ struct workqueue_struct *wq_security;
+ struct work_struct gtk_rekey_work;
+
+ struct usb_encryption_descriptor *ccm1_etd;
+};
+
+#define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd)
+
+
+extern int wusbhc_create(struct wusbhc *);
+extern int wusbhc_b_create(struct wusbhc *);
+extern void wusbhc_b_destroy(struct wusbhc *);
+extern void wusbhc_destroy(struct wusbhc *);
+extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *,
+ struct wusb_dev *);
+extern void wusb_dev_sysfs_rm(struct wusb_dev *);
+extern int wusbhc_sec_create(struct wusbhc *);
+extern int wusbhc_sec_start(struct wusbhc *);
+extern void wusbhc_sec_stop(struct wusbhc *);
+extern void wusbhc_sec_destroy(struct wusbhc *);
+extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb,
+ int status);
+void wusbhc_reset_all(struct wusbhc *wusbhc);
+
+int wusbhc_pal_register(struct wusbhc *wusbhc);
+void wusbhc_pal_unregister(struct wusbhc *wusbhc);
+
+/*
+ * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone
+ *
+ * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
+ *
+ * This is a safe assumption as @usb_dev->bus is referenced all the
+ * time during the @usb_dev life cycle.
+ */
+static inline
+struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev)
+{
+ struct usb_hcd *usb_hcd;
+ usb_hcd = bus_to_hcd(usb_dev->bus);
+ return usb_get_hcd(usb_hcd);
+}
+
+/*
+ * Increment the reference count on a wusbhc.
+ *
+ * @wusbhc's life cycle is identical to that of the underlying usb_hcd.
+ */
+static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc)
+{
+ return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL;
+}
+
+/*
+ * Return the wusbhc associated to a @usb_dev
+ *
+ * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
+ *
+ * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down.
+ * WARNING: referenced at the usb_hcd level, unlocked
+ *
+ * FIXME: move offline
+ */
+static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev)
+{
+ struct wusbhc *wusbhc = NULL;
+ struct usb_hcd *usb_hcd;
+ if (usb_dev->devnum > 1 && !usb_dev->wusb) {
+ /* but root hubs */
+ dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum,
+ usb_dev->wusb);
+ BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb);
+ }
+ usb_hcd = usb_hcd_get_by_usb_dev(usb_dev);
+ if (usb_hcd == NULL)
+ return NULL;
+ BUG_ON(usb_hcd->wireless == 0);
+ return wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+}
+
+
+static inline void wusbhc_put(struct wusbhc *wusbhc)
+{
+ usb_put_hcd(&wusbhc->usb_hcd);
+}
+
+int wusbhc_start(struct wusbhc *wusbhc);
+void wusbhc_stop(struct wusbhc *wusbhc);
+extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *);
+
+/* Device connect handling */
+extern int wusbhc_devconnect_create(struct wusbhc *);
+extern void wusbhc_devconnect_destroy(struct wusbhc *);
+extern int wusbhc_devconnect_start(struct wusbhc *wusbhc);
+extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc);
+extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr,
+ struct wusb_dn_hdr *dn_hdr, size_t size);
+extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port);
+extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
+ void *priv);
+extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
+ u8 addr);
+
+/* Wireless USB fake Root Hub methods */
+extern int wusbhc_rh_create(struct wusbhc *);
+extern void wusbhc_rh_destroy(struct wusbhc *);
+
+extern int wusbhc_rh_status_data(struct usb_hcd *, char *);
+extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16);
+extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned);
+
+/* MMC handling */
+extern int wusbhc_mmcie_create(struct wusbhc *);
+extern void wusbhc_mmcie_destroy(struct wusbhc *);
+extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt,
+ struct wuie_hdr *);
+extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *);
+
+/* Bandwidth reservation */
+int wusbhc_rsv_establish(struct wusbhc *wusbhc);
+void wusbhc_rsv_terminate(struct wusbhc *wusbhc);
+
+/*
+ * I've always said
+ * I wanted a wedding in a church...
+ *
+ * but lately I've been thinking about
+ * the Botanical Gardens.
+ *
+ * We could do it by the tulips.
+ * It'll be beautiful
+ *
+ * --Security!
+ */
+extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *,
+ struct wusb_dev *);
+extern void wusb_dev_sec_rm(struct wusb_dev *) ;
+extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *,
+ struct wusb_ckhdid *ck);
+void wusbhc_gtk_rekey(struct wusbhc *wusbhc);
+int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
+
+
+/* WUSB Cluster ID handling */
+extern u8 wusb_cluster_id_get(void);
+extern void wusb_cluster_id_put(u8);
+
+/*
+ * wusb_port_by_idx - return the port associated to a zero-based port index
+ *
+ * NOTE: valid without locking as long as wusbhc is referenced (as the
+ * number of ports doesn't change). The data pointed to has to
+ * be verified though :)
+ */
+static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc,
+ u8 port_idx)
+{
+ return &wusbhc->port[port_idx];
+}
+
+/*
+ * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to
+ * a port_idx.
+ *
+ * USB stack USB ports are 1 based!!
+ *
+ * NOTE: only valid for WUSB devices!!!
+ */
+static inline u8 wusb_port_no_to_idx(u8 port_no)
+{
+ return port_no - 1;
+}
+
+extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *,
+ struct usb_device *);
+
+/*
+ * Return a referenced wusb_dev given a @usb_dev
+ *
+ * Returns NULL if the usb_dev is being torn down.
+ *
+ * FIXME: move offline
+ */
+static inline
+struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev)
+{
+ struct wusbhc *wusbhc;
+ struct wusb_dev *wusb_dev;
+ wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+ if (wusbhc == NULL)
+ return NULL;
+ mutex_lock(&wusbhc->mutex);
+ wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
+ mutex_unlock(&wusbhc->mutex);
+ wusbhc_put(wusbhc);
+ return wusb_dev;
+}
+
+/* Misc */
+
+extern struct workqueue_struct *wusbd;
+#endif /* #ifndef __WUSBHC_H__ */